Samtoto / laravel-review

0 stars 0 forks source link

Day 5 #7

Open Samtoto opened 4 years ago

Samtoto commented 4 years ago

Day 5

file: vendor/laravel/framework/src/Illuminate/Foundation/Application.php

/**
 * Create a new Illuminate application instance.
 *
 * @param  string|null  $basePath
 * @return void
 */
public function __construct($basePath = null)
{
    if ($basePath) {
        $this->setBasePath($basePath);
    }
    // 程序运行到这里了
    // 继续看下面的 $this->registerBaseBindings();

    $this->registerBaseBindings();
    $this->registerBaseServiceProviders();
    $this->registerCoreContainerAliases();
}

/**
 * Register the basic bindings into the container.
 *
 * @return void
 */
protected function registerBaseBindings()
{
    // `static::` 的用法见页尾
    //
    static::setInstance($this);

    /* 折叠 */
}

这个 static::setInstance 调用的是 Container 类的方法 file: vendor/laravel/framework/src/Illuminate/Container/Container.php


    /**
     * Set the shared instance of the container.
     *
     * @param  \Illuminate\Contracts\Container\Container|null  $container
     * @return \Illuminate\Contracts\Container\Container|static
     */
    public static function setInstance(ContainerContract $container = null)
    {
        // 所以 Application::instance = $this;
        // 并返回了,只不过被返回的 $container 没有被接收。
        return static::$instance = $container;
    }

返回刚才的文件继续

file: vendor/laravel/framework/src/Illuminate/Foundation/Application.php

/**
 * Register the basic bindings into the container.
 *
 * @return void
 */
protected function registerBaseBindings()
{
    // `static::` 的用法见页尾
    //
    static::setInstance($this);
    // 此时 Application::instance = Application
    // 通过 Day 3 知道 $this->instance 的作用是:
    // $this->instances['app'] = $this;
    $this->instance('app', $this);

    // $this->instances['Illuminate\Container\Container'] = $this;
    $this->instance(Container::class, $this);
    // 这是个还没见过的方法, 这里相当于 $this->singleton('Illuminate\Foundation\Mix');
    $this->singleton(Mix::class);
    /* 折叠 */
}

找到 $this->singleton()

file: vendor/laravel/framework/src/Illuminate/Container/Container.php

/**
 * Register a shared binding in the container.
 *
 * @param  string  $abstract
 * @param  \Closure|string|null  $concrete
 * @return void
 */
public function singleton($abstract, $concrete = null)
{
    // 相当于 $this->bind('Illuminate\Foundation\Mix', null, true);
    $this->bind($abstract, $concrete, true);
}

进入文件,并找到该方法。 file: vendor/laravel/framework/src/Illuminate/Container/Container.php


/**
 * 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)
{
    // 此时有如下参数
    $abstract = 'Illuminate\Foundation\Mix';
    $concrete = null;
    $shared = true;
    /////////////
    // 这里调用了 $this->dropStaleInstances('Illuminate\Foundation\Mix');
    $this->dropStaleInstances($abstract);
    /**折叠**/
}

/**
 * Drop all of the stale instances and aliases.
 *
 * @param  string  $abstract
 * @return void
 */
protected function dropStaleInstances($abstract)
{
    // 先使用dd 打印下这两个变量
    dump($this->instances);
    dd($this->aliases);
    // 打印之后发现根本没有 $this->instances['Illuminate\Foundation\Mix']
    // 也没有 $this->aliases['Illuminate\Foundation\Mix']
    // 所以这句话执行后并没有改变什么。
    unset($this->instances[$abstract], $this->aliases[$abstract]);
}

回到 $this->bind() file: vendor/laravel/framework/src/Illuminate/Container/Container.php

/**
 * 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
        );
    };
}

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() 打印看看

array:1 [▼
  "Illuminate\Foundation\Mix" => array:2 [▼
    "concrete" => Closure($container, $parameters = []) {#5 ▼
      class: "Illuminate\Container\Container"
      this: Illuminate\Foundation\Application {#1 …}
      use: {▼
        $abstract: "Illuminate\Foundation\Mix"
        $concrete: "Illuminate\Foundation\Mix"
      }
    }
    "shared" => true
  ]
]

接下来继续运行语句

// 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);
}

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)有了变化,即:

array:1 [▼
  "Illuminate\Foundation\Mix" => array:2 [▼
    "concrete" => Closure($container, $parameters = []) {#5 ▼
      class: "Illuminate\Container\Container"
      this: Illuminate\Foundation\Application {#1 …}
      use: {▼
        $abstract: "Illuminate\Foundation\Mix"
        $concrete: "Illuminate\Foundation\Mix"
      }
    }
    "shared" => true
  ]
]

同理,继续执行

$this->singleton(PackageManifest::class, function () {
    return new PackageManifest(
        new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
    );
});

执行后 $this->bindings 数组将增加一组,如下:

"Illuminate\Foundation\PackageManifest" => array:2 [▼
      "concrete" => Closure() {#12 ▼
        class: "Illuminate\Foundation\Application"
        this: Illuminate\Foundation\Application {#1}
      }
      "shared" => true
    ]

继续回到 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:: 的用法

<?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 的用法

unset()

销毁指定的变量。—— https://www.php.net/manual/zh/function.unset.php

$arr = ['name'=> 'oceanpi', 'age'=> 18, 'home'=> 'earth'];
unset($arr['name']);
var_dump($arr);

OUTPUT:
array:2 [▼
  "age" => "18"
  "home" => "earth"
]
Samtoto commented 4 years ago
laravel流程图-day5