为什么Container::getInstance()可以返回应用程序类

edw*_*uan 4 php static static-methods laravel laravel-5

我想知道为什么Container::getInstance()可以返回应用程序类。

\n\n

例如:

\n\n

我想做一个哈希str,我想知道它们是如何工作的\xef\xbc\x9a

\n\n
app('hash')->make('password');\n
Run Code Online (Sandbox Code Playgroud)\n\n

我在 laravel \xef\xbc\x9a 中找到了源代码

\n\n

供应商/laravel/framework/src/Illuminate/Foundation/helpers.php

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

我不知道Container::getInstance()会返回什么,那么我dd\xef\xbc\x88Container::getInstance()\xef\xbc\x89知道它会返回一个应用程序类,但我不知道它们是如何工作的。

\n

Dmy*_*bak 5

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

描述截至 Laravel 框架版本 5.3.24 为止。

为什么调用app(),然后调用Container::getInstance()返回对象,应用程序的实例?例如,为什么

Route::get('/', function () {
    var_dump(app());
});
Run Code Online (Sandbox Code Playgroud)

输出:

object(Illuminate\Foundation\Application)
...
Run Code Online (Sandbox Code Playgroud)

因为……而在这里我们必须一步一步地走下去才能理解一切。

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

    $app = require_once __DIR__.'/../bootstrap/app.php';
    
    Run Code Online (Sandbox Code Playgroud)
  3. /bootstrap/app.php有以下几行:

    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    
    Run Code Online (Sandbox Code Playgroud)
  4. 当实例化 $app 对象时,Illuminate\Foundation\Application将调用类构造函数。

/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
            // ...
        }
        // ...
    }
Run Code Online (Sandbox Code Playgroud)
  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;
        }
        // ...
    }
Run Code Online (Sandbox Code Playgroud)
  1. 现在,假设我们在路由文件中写入了以下几行。 /routes/web.php

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

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();
        }
        // ...
    }
    // ...
Run Code Online (Sandbox Code Playgroud)
  1. 现在我们回到了 Container 类 /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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

步骤 16-19 的一些重要注意事项。

重要提示1!

静态关键字

将类属性或方法声明为静态可以使它们无需实例化类即可访问。

重要提示2!

static::$instance = new static;与在步骤 13 中调用我们的 app() 函数无关。并且一开始对我来说有点误导......

但要注意的是,它使用了Late Static Bindings