Samtoto / laravel-review

0 stars 0 forks source link

Day 4 #4

Open Samtoto opened 4 years ago

Samtoto commented 4 years ago

Day 4

composer 的内容已经基本看过了,在 public/index.php 中,进行到这里了。

$app = require_once __DIR__.'/../bootstrap/app.php';

bootstrap/app.php


$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

这里的 Illuminate\Foundation\Applicationvendor/laravel/framework/src/Illuminate/Foundation/Application.php

class Application extends Container implements ApplicationContract, CachesConfiguration, CachesRoutes, HttpKernelInterface
{ /***/ }

这里看到,Illuminate\Foundation\ApplicationApplication 类继承了 Illuminate\Container\Container 类。 Illuminate\Foundation\ApplicationApplication 实现了如下接口:

Illuminate\Contracts\Foundation\Application Illuminate\Contracts\Foundation\CachesConfiguration Illuminate\Contracts\Foundation\CachesRoutes Symfony\Component\HttpKernel\HttpKernelInterface

而继承的 Illuminate\Container\ContainerContainer 类实现了如下接口:

Illuminate\ArrayAccess Illuminate\Contracts\Container\Container

先不看这些接口,因为这些接口只是相当于一个类的框架(骨头),先看实现。 那么就要找 Illuminate\Foundation\ApplicationIlluminate\Container\Container__construct

Illuminate\Foundation\ApplicationApplication 类有构造方法,而 Illuminate\Container\ContainerContainer 没有构造方法。 所以先看这里vendor/laravel/framework/src/Illuminate/Foundation/Application.php__construct


public function __construct($basePath = null)
{
    if ($basePath) {
        $this->setBasePath($basePath);
    }
    /******/
}

这里调用了 $this->setBasePath, 并传入了 basePath 即 laravel 项目的根目录 / (非网站根目录 /public); 而在 $this->setBasePath 中是这样的:

// $basePath = '/';
public function setBasePath($basePath)
{
    // 故此 $this->basePath = '/';
    $this->basePath = rtrim($basePath, '\/');
    // 这里调用了下面的方法
    $this->bindPathsInContainer();
    /***折叠先****/
}

$this->bindPathsInContainer()

/**
 * Bind all of the application paths in the container.
 *
 * @return void
 */
protected function bindPathsInContainer()
{
    $this->instance('path', $this->path());
    /********/
    $this->instance('path.bootstrap', $this->bootstrapPath());
}

当然也可以直接在 app.php 中使用 dd() 查看,$app->instance 有哪些属性

先看第一条 $this->instance('path', $this->path()); 'path' 不用说了,是个 string ,重点先看这个 $this->path()

/**
 * Get the path to the application "app" directory.
 *
 * @param  string  $path
 * @return string
 */
// 这里看到 doc 显示,return 了一个 string, 而传入的 $path 是空的

public function path($path = '')
{
    // 三元运算符,所以这里的 $appPath == '/path/to/var/www/app'
    $appPath = $this->appPath ?: $this->basePath.DIRECTORY_SEPARATOR.'app';
    // $path == '' 所以直接传回了 $appPath
    return $appPath.($path ? DIRECTORY_SEPARATOR.$path : $path);
}

此时 我们知道了,在$this->instance() 中的全部参数,即: $this->instance('path', '/path/to/var/www/app');

这里的 $this->instance('path', '/path/to/var/www/app') 调用的是父类即 Illuminate\Container\ContainerContainer 的 instance 方法 在 Illuminate\Container\ContainerContainer 类文件 vendor/laravel/framework/src/Illuminate/Container/Container.php 中找到该方法

https://github.com/Samtoto/laravel-review/blob/8ee3b5dd61b78bfb023984ed573eb7dff442011a/laravel/vendor/laravel/framework/src/Illuminate/Container/Container.php#L404-L429

这里调用了 $this->removeAbstractAlias($abstract); 也就是 $this->removeAbstractAlias('path');

/**
 * Remove an alias from the contextual binding alias cache.
 *
 * @param  string  $searched
 * @return void
 */
// 由于 $this->aliases 和 $abstractAliases 都为空,所以这里返回了 false
// 使用 dd() 测试
protected function removeAbstractAlias($searched)
{
    if (! isset($this->aliases[$searched])) {
        // 这里直接返回了。
        return;
    }

    foreach ($this->abstractAliases as $abstract => $aliases) {
        foreach ($aliases as $index => $alias) {
            if ($alias == $searched) {
                unset($this->abstractAliases[$abstract][$index]);
            }
        }
    }
}

回到 $this->instance('path', '/path/to/var/www/app')

/**
 * Register an existing instance as shared in the container.
 *
 * @param  string  $abstract
 * @param  mixed  $instance
 * @return mixed
 */
public function instance($abstract, $instance)
{
    /* 折叠 */
    // 程序继续运行,执行到此。

    $isBound = $this->bound($abstract);

    unset($this->aliases[$abstract]);

    // We'll check to determine if this type has been bound before, and if it has
    // we will fire the rebound callbacks registered with the container and it
    // can be updated with consuming classes that have gotten resolved here.
    $this->instances[$abstract] = $instance;

    if ($isBound) {
        $this->rebound($abstract);
    }

    return $instance;
}

该运行 $this->bound

/**
 * Determine if the given abstract type has been bound.
 *
 * @param  string  $abstract
 * @return bool
 */
public function bound($abstract)
{
    // $this->bindings == $this->instances == [];
    // 通过下面的 isAlias 可以知道,此时这里相当于  return false || false || false;
    // 返回了 false
    return isset($this->bindings[$abstract]) ||
            isset($this->instances[$abstract]) ||
            $this->isAlias($abstract);
}

/**
 * Determine if a given string is an alias.
 *
 * @param  string  $name
 * @return bool
 */
public function isAlias($name)
{
    return isset($this->aliases[$name]);
}

回到 $this->instance('path', '/path/to/var/www/app')

/**
 * Register an existing instance as shared in the container.
 *
 * @param  string  $abstract
 * @param  mixed  $instance
 * @return mixed
 */
public function instance($abstract, $instance)
{
    /* 折叠 */
    // 程序继续运行,执行到此。
    // 又清空了一遍。
    unset($this->aliases[$abstract]);

    // We'll check to determine if this type has been bound before, and if it has
    // we will fire the rebound callbacks registered with the container and it
    // can be updated with consuming classes that have gotten resolved here.

    // 此时 $this->instances['path'] = '/app'
    $this->instances[$abstract] = $instance;
    // $isBound == false
    if ($isBound) {
        $this->rebound($abstract);
    }
    // return '/path/to/var/www/app';
    return $instance;
}

回到 $this->instance() 被调用的位置,如下:

/**
 * Bind all of the application paths in the container.
 *
 * @return void
 */
protected function bindPathsInContainer()
{
    $this->instance('path', $this->path());
    /********/
    $this->instance('path.bootstrap', $this->bootstrapPath());
}

这里可以举一反三知道, 对 (array) $this->instances 进行了赋值. 通过 dd($this->instances) 打印一下看看

array:9 [
  "path" => "/path/to/var/www/app"
  "path.base" => "/path/to/var/www"
  "path.lang" => "/path/to/var/www/resources/lang"
  "path.config" => "/path/to/var/www/config"
  "path.public" => "/path/to/var/www/public"
  "path.storage" => "/path/to/var/www/storage"
  "path.database" => "/path/to/var/www/database"
  "path.resources" => "/path/to/var/www/resources"
  "path.bootstrap" => "/path/to/var/www/bootstrap"
]

回到调用了 $this->bindPathsInContainer 的位置

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->registerBaseServiceProviders();
    $this->registerCoreContainerAliases();
}

/**
 * Set the base path for the application.
 *
 * @param  string  $basePath
 * @return $this
 */
public function setBasePath($basePath)
{
    $this->basePath = rtrim($basePath, '\/');

    $this->bindPathsInContainer();

    return $this;
}

可以看到,这里直接返回了,回到 __construct 继续 $this->registerBaseBindings();

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

/**
 * Register the basic bindings into the container.
 *
 * @return void
 */
protected function registerBaseBindings()
{
    static::setInstance($this);

    $this->instance('app', $this);

    $this->instance(Container::class, $this);
    $this->singleton(Mix::class);

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