/**
* Register a binding with the container.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bind($abstract, $concrete = null, $shared = false)
{
$this->dropStaleInstances($abstract);
// 执行了上面的语句,但是并没有任何改变。
// If no concrete type was given, we will simply set the concrete type to the
// abstract type. After that, the concrete type to be registered as shared
// without being forced to state their classes in both of the parameters.
if (is_null($concrete)) { // true
$concrete = $abstract;
}
// 所以此时有如下变化
$abstract = 'Illuminate\Foundation\Mix';
$concrete = 'Illuminate\Foundation\Mix';
$shared = true;
////////////////////////////////////////////
// If the factory is not a Closure, it means it is just a class name which is
// bound into this container to the abstract type and we will just wrap it
// up inside its own Closure to give us more convenience when extending.
if (! $concrete instanceof Closure) {
// 通过打印,设置断点,这里被执行了。看看下面的 getClosure 都做了什么
// 此时这里相当于
// $concrete = $this->getClosure('Illuminate\Foundation\Mix', 'Illuminate\Foundation\Mix');
$concrete = $this->getClosure($abstract, $concrete);
}
/****折叠****/
}
/**
* Get the Closure to be used when building a type.
*
* @param string $abstract
* @param string $concrete
* @return \Closure
*/
protected function getClosure($abstract, $concrete)
{
// 此时
$abstract = 'Illuminate\Foundation\Mix';
$concrete = 'Illuminate\Foundation\Mix';
/**********/
// 返回了这样的一个匿名方法
return function ($container, $parameters = []) use ($abstract, $concrete) {
if ($abstract == $concrete) { // true
return $container->build($concrete);
}
return $container->resolve(
$concrete, $parameters, $raiseEvents = false
);
};
}
// If the abstract type was already resolved in this container we'll fire the
// rebound listener so that any objects which have already gotten resolved
// can have their copy of the object updated via the listener callbacks.
if ($this->resolved($abstract)) {
$this->rebound($abstract);
}
$this->singleton(PackageManifest::class, function () {
return new PackageManifest(
new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
);
});
<?php
class Foo
{
public static $war = false;
public static function bar()
{
return __FUNCTION__;
}
public function doSth()
{
if (! static::$war ) {
echo static::bar();
}
}
}
$foo = new Foo;
$foo->doSth();
?>
OUTPUT: bar
类似于 $this 的用法
Day 5
file: vendor/laravel/framework/src/Illuminate/Foundation/Application.php
这个
static::setInstance
调用的是Container
类的方法file: vendor/laravel/framework/src/Illuminate/Container/Container.php
返回刚才的文件继续
file: vendor/laravel/framework/src/Illuminate/Foundation/Application.php
找到
$this->singleton()
file: vendor/laravel/framework/src/Illuminate/Container/Container.php
进入文件,并找到该方法。
file: vendor/laravel/framework/src/Illuminate/Container/Container.php
回到
$this->bind()
file: vendor/laravel/framework/src/Illuminate/Container/Container.php
https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Container/Container.php#L214-L252
接下来继续运行
$this->bind()
当中的内容$this->bindings[$abstract] = compact('concrete', 'shared');
这里是将$this->bindings
赋值了。在该语句下使用dd()
打印看看接下来继续运行语句
https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Container/Container.php#L174-L188
https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Container/Container.php#L203-L212
可以看到,在
$this->resolved()
函数中传入了$abstract
即'Illuminate\Foundation\Mix'
,传入后即执行了$this->isAlias()
,由于此时$this->aliases
还是空,所以返回false
, 即$abstract = $this->getAlias($abstract);
不会执行。 之后执行了return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]);
. 在 return 之前,打印看看这个boolean。得知,最终return false;
所以,回到上层函数$this->bind
可以看到程序不会执行 if 语句里的内容。 再回到上层函数https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L184-L203
此时(运行过
$this->singleton(Mix::class);
后),Application
中的 bindings 属性(继承自 Container)有了变化,即:同理,继续执行
执行后
$this->bindings
数组将增加一组,如下:继续回到
Application
的__construct()
中https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L157-L172
继续执行
$this->registerBaseServiceProviders();
https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L205-L215
执行了三个
$this->register
,可以看到这里的三个参数,分别对应到了三个 service provider, 它们是 事件服务供应者、日志服务供应者和路由服务供应者。这里像是用到了依赖注入的设计模式。看一看这个
EventServiceProveider.php
https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Events/EventServiceProvider.php#L1-L23 它继承了抽象类ServiceProvider
https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Support/ServiceProvider.php#L12-L44 这里看到,new EventServiceProvider($this)
这里相当于,EventServiceProvider 的 属性 app 是当前的 Application。看下这个
$this->register
函数的全貌https://github.com/Samtoto/laravel-review/blob/36b34f11ae3bbbb87449b4ba2cd7626e4deb11f7/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php#L607-L654
扩展
static::
的用法unset()
销毁指定的变量。—— https://www.php.net/manual/zh/function.unset.php