为什么Container :: getInstance()返回一个应用程序类

时间:2016-06-10 16:25:27

标签: php laravel laravel-5 static static-methods

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

例如:

我想制作一个hash str,我想知道它们是如何工作的:

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

我在laravel中找到了源代码:

供应商/ laravel /框架/ SRC /照亮/粉底/ 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()会返回什么,然后我dd(Container::getInstance())我知道它会返回一个应用程序类,但我不知道它们是如何工作的。

2 个答案:

答案 0 :(得分:1)

也许我的答案有点迟了,但无论如何。

描述是Laravel框架版本5.3.24的最新版本。

为什么调用app(),然后调用Container::getInstance()返回对象,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类构造函数。

  6. /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
    2. /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
        });
        
      2. 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. 现在我们回到我们的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;
          }
          
        2. 步骤16-19的一些重要说明。

          重要提示1!

          Static Keyword

            

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

          重要提示2!

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

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

答案 1 :(得分:0)

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

无需复杂:这可以将任何类绑定到该Container实例中:

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

那么你可以"解决"那个类出了容器:

app()->make('MyModule);

但请记住,有几种方法可以做到这一点,使用不同的模式目标,这只是概念的基本演示。