该篇属于《Laravel底层核心技术实战揭秘》这一课程《laravel底层核心概念解析》这一章的扩展阅读。由于要真正学好laravel底层,有些PHP相关的知识必须得了解,考虑到学员们的基础差异,为了避免视频当中过于详细而连篇累牍,故将一些laravel底层实现相关的PHP知识点以文章形式呈现,供大家预习和随时查阅。

之前我们讲过静态调用绑定(late static binding),nice,现在来考考你呗~ smirk

<?php
class Foo {
	protected static $instance;

	public static function setInstance($ins)
	{
		static::$instance = $ins;
	}

	public static function getInstance()
	{
		return static::$instance;
	}
}
class Bar extends Foo {
	
}

Bar::setInstance('pilishen.com');
echo Bar::getInstance() .'<br>';
echo Foo::getInstance() .'<br>';
?>

你说两个输出结果分别是啥呢?

echo Bar::getInstance() .'<br>';输出的肯定是pilishen.com,问题是echo Foo::getInstance() .'<br>';.

我们知道static::指向的是实际调用它的class,所以Bar::setInstance('pilishen.com');执行的时候,在setInstance()方法里相当于是Bar::$instance = 'pilishen.com',也即是class Bar的静态属性$instance设置成了pilishen.com,而父类class Foo的静态属性$instance没动着它,所以应该还是空的,对吧?

现实是残酷的: open_mouth

pilishen.com
pilishen.com

好吧,现实是需要接受的,继续作! smiling_imp

...
class Baz extends Foo {
	
}


Bar::setInstance('pilishen.com');
echo Bar::getInstance() .'<br>';
echo Foo::getInstance() .'<br>';

echo '<hr>';
Baz::setInstance('laravel');
echo Baz::getInstance() .'<br>';
echo Bar::getInstance() .'<br>';
echo Foo::getInstance() .'<br>';
?>

我们又搞了一个class Baz,也是扩展了class Foo,然后Baz::setInstance('laravel');,这个时候很显然Baz$instancelaravel了,问题是BarFoo的呢?我们知道它两个之前都是pilishen.com,再来接受下现实? scream

pilishen.com
pilishen.com

laravel
laravel
laravel

好吧,牵一发动全身!子类能改变父类?!子类能改变子类?!厉害了哦~ thumbsup

为了测试这只是静态属性的问题,也即证明一下我们传统的关于属性继承的思路没错,我们改一下:

<?php
class Foo {
	protected $instance='Null';

	public function setInstance($ins)
	{
		$this->instance = $ins;
	}

	public function getInstance()
	{
		return $this->instance;
	}
}
class Bar extends Foo {
	
}
class Baz extends Foo {
	
}

$bar = new Bar;
$bar->setInstance('pilishen.com');
echo $bar->getInstance() .'<br>';
echo (new Foo)->getInstance() .'<br>';

echo '<hr>';
$baz = new Baz;
$baz->setInstance('laravel');
echo $baz->getInstance() .'<br>';
echo $bar->getInstance() .'<br>';
echo (new Foo)->getInstance() .'<br>';
?>

现在的现实就是可以接受的了:

pilishen.com
Null

laravel
pilishen.com
Null

所以,静态属性的继承跟我们默认想象的不一样哦: sunglasses

尽管我们在子类里可以获取它,可以修改它,但是这个它,指向的都是父类里的那个静态属性,确实是子类能改变父类,子类能改变子类。也或者说,所有的父类和子类,都是共享这一个静态属性。

当然,上面的情况仅发生在你的子类里,没有额外定义一个同名静态属性的情况下,如果这样:

<?php
class Foo {
	protected static $instance='null';

	public static function setInstance($ins)
	{
		static::$instance = $ins;
	}

	public static function getInstance()
	{
		return static::$instance;
	}
}
class Bar extends Foo {
	protected static $instance;
}
class Baz extends Foo {
	protected static $instance;
}


Bar::setInstance('pilishen.com');
echo Bar::getInstance() .'<br>';
echo Foo::getInstance() .'<br>';

echo '<hr>';
Baz::setInstance('laravel');
echo Baz::getInstance() .'<br>';
echo Bar::getInstance() .'<br>';
echo Foo::getInstance() .'<br>';
?>

这里我们在子类里面都额外定义了一个同名的$instance,这个时候就是各自的是各自的了,就不是共享了:

pilishen.com
null

laravel
pilishen.com
null

好了,知道这些个有什么用呢?

laravel里大量使用了静态属性,当然也包括静态调用绑定,那么你在查看源码的时候就要注意这一点喽~父类和子类是共享的一个静态属性吗?还是子类里面有重新定义呢?子类更改静态属性,会影响父类吗? sleeping

最简单的,laravel如何保证整个程序,那么多个类,他们在运行的时候都是用的同一个laravel实例本身呢?都是同一个$app呢?现在明白了吧~ unamused

不明白也不要紧,回头我们在《Laravel底层核心技术实战揭秘》中一一详解,记得有这么回事就好~ muscle