为什么 Container::getInstance() return 一个应用程序 class

Why can Container::getInstance() return an application class

我在想为什么 Container::getInstance() 可以 return 一个应用程序 class。

例如:

我想做一个hash str,想知道它们是怎么工作的:

app('hash')->make('password');

我在laravel找到了源码:

vendor/laravel/framework/src/Illuminate/Foundation/helpers.php

if (! function_exists('app')) {
    /**
     * Get the available container instance.
     *
     * @param  string  $make
     * @param  array   $parameters
     * @return mixed|\Illuminate\Foundation\Application
     */
    function app($make = null, $parameters = [])
    {
        if (is_null($make)) {
            return Container::getInstance();
        }

        return Container::getInstance()->make($make, $parameters);

    }
}

我不知道 Container::getInstance() 会 return 是什么,然后我 dd(Container::getInstance()) 我知道它可以 return 一个应用程序 class,但是我不知道它们是如何工作的。

应用程序 class (Illuminate\Foundation\Application) 扩展容器 class。这是框架的核心,允许所有依赖注入魔法,它遵循 Sigleton 模式,这意味着当您请求 Application 对象时(使用 app() 辅助函数,或更内部 Container::getInstance() ) 在你的代码中的任何地方你都会得到相同的全局实例。

无需复杂:这让您将任何 class 绑定到该 Container 实例中:

app()->bind('MyModule', new MyModuleInstace());

那么您可以 "resolve" class 从容器中取出:

app()->make('MyModule);

但请记住,有多种方法可以使用不同的模式目标来执行此操作,这只是概念的基本演示。

也许我的回答有点晚了,但无论如何。

描述截至 Laravel 框架版本 5.3.24。

为什么 调用app(),然后调用Container::getInstance() returns 对象,Application 实例? 例如,为什么

Route::get('/', function () {
    var_dump(app());
});

输出:

object(Illuminate\Foundation\Application)
...

因为...而这里我们必须一步一步来了解一切。

  1. 用户发起网络请求。请求由 /public/index.php
  2. 处理
  3. /public/index.php 包含以下内容:

    $app = require_once __DIR__.'/../bootstrap/app.php';
    
  4. /bootstrap/app.php 有以下几行:

    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    
  5. 当 $app 对象被实例化时,Illuminate\Foundation\Application class 构造函数被调用。

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

    class Application extends Container implements ...
    {
        // ...
        public function __construct($basePath = null)
        {
            // 5. constructor triggers the following method:
            $this->registerBaseBindings();
            // ...
        }
        // ...
        protected function registerBaseBindings()
        {
            // 6. which then triggers the following:
            static::setInstance($this);
            // 7. Important! $this points to class Application here
            // and is passed to Container
            // ...
        }
        // ...
    }
  1. static::setInstance($this); 指的是 class Container,因为 class Application extends Container

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

    class Container implements ...
    {
        // ...
        // 11. $instance now contains an object,
        // which is an instance of Application class
        protected static $instance;
        // ...
        public static function setInstance(ContainerContract $container = null)
        {
            // 9. $container = Application here, because it has been passed
            // from class Application while calling static::setInstance($this);
            // 10. Thus, static::$instance is set to Application here
            return static::$instance = $container;
        }
        // ...
    }

  1. 现在,假设我们在路由文件中写入了以下几行。 /routes/web.php

    Route::get('/', function () {
        dd(app()); // 13. We a calling an app() helper function
    });
    

14 调用 app() 将我们带到 /vendor/laravel/framework/src/Illuminate/Foundation/helpers.php

    // ...
    /** @return mixed|\Illuminate\Foundation\Application */
    function app($make = null, $parameters = [])
    {
        // 15. $make is null, so this is the case
        if (is_null($make)) {
            // 16. The following static method is called:
            return Container::getInstance();
        }
        // ...
    }
    // ...
  1. 现在我们回到了容器中class /vendor/laravel/framework/src/Illuminate/Container/Container.php

    public static function getInstance()
    {
        // 18. Important!
        // To this point static::$instance is NOT null,
        // because it has already been set (up to "step 11").
        if (is_null(static::$instance)) {
            static::$instance = new static; // Thus, we skip this.
        }
        // 19. static::$instance is returned
        // that contains an object,
        // which is an instance of Application class
        return static::$instance;
    }
    

步骤 16-19 的一些重要说明。

重要提示1!

Static Keyword

Declaring class properties or methods as static makes them accessible without needing an instantiation of the class.

重要提示2!

static::$instance = new static; 与在第 13 步中调用我们的 app() 函数无关。起初对我来说有点误导...

但请注意,它使用了 Late Static Bindings