Laravel 4集装箱内部工作

时间:2013-08-12 14:53:55

标签: laravel closures inversion-of-control containers

我一直在研究laravel 4容器,以获得更多关于laravel内部的知识,并提高我自己编写更好代码的技能。

然而,我无法理解3个相似的代码片段。 我将使用最小的片段来保持这个问题的清洁。

类似的问题可以在下面的链接中找到。虽然人们回答了正确的答案,但我不满足于简单地“知道如何使用它,但不知道它是如何工作的”。所以我真的希望有人可以解释这一切。

Question 1 Question 2

<?php namespace Illuminate\Container; use Closure, ArrayAccess, ReflectionParameter;

class BindingResolutionException extends \Exception {}

class Container implements ArrayAccess {

    /**
     * Wrap a Closure such that it is shared.
     *
     * @param  Closure  $closure
     * @return Closure
     */
    public function share(Closure $closure)
    {
        return function($container) use ($closure)
        {
            // We'll simply declare a static variable within the Closures and if
            // it has not been set we'll execute the given Closure to resolve
            // the value and return it back to the consumers of the method.
            static $object;

            if (is_null($object))
            {
                $object = $closure($container);
            }

            return $object;
        };
    } 

}

share方法如何知道该函数中的$ container变量实际上是Illuminate \ Container的一个实例?它没有在该函数的范围内定义。 它也没有在以下示例usecase中定义(无论如何都没有帮助)

class AuthServiceProvider extends ServiceProvider{

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app['auth'] = $this->app->share(function($app)
        {
            // Once the authentication service has actually been requested by the developer
            // we will set a variable in the application indicating such. This helps us
            // know that we need to set any queued cookies in the after event later.
            $app['auth.loaded'] = true;

            return new AuthManager($app);
        });
    }

}

我希望有不同的实现方式,所以

class MyContainer{

    public function share(Closure $closure)
    {
        $container = $this;

        return function() use ($closure, $container)
        {
            static $object;

            if(is_null($object))
            {
                $object = $closure($container);
            }

            return $object;
        };
    }

}

$closure = function($container)
{
    var_dump($container);
};

$container = new MyContainer();
call_user_func($container->share($closure));
//dumps an instance of MyContainer -> which is the wanted behaviour

$container = new Illuminate\Container\Container();
call_user_func($container->share($closure));
//Throws a warning AND a notice
//Warning: Missing argument 1 for Illuminate\Container\Container::Illuminate\Container\{closure}() in /Users/thomas/Sites/Troll/vendor/illuminate/container/Illuminate/Container/Container.php on line 128
//NOTICE: Notice: Undefined variable: container in /Users/thomas/Sites/Troll/vendor/illuminate/container/Illuminate/Container/Container.php on line 137
//and even worse the output of the var_dump is NULL

我在理解extend和bind方法时遇到同样的问题,它们都具有相同的实现,即传递一个不存在的参数作为闭包参数,但是我无法理解它是如何解析容器实例本身的? / p>

1 个答案:

答案 0 :(得分:1)

Container::share()的返回值是一个带有一个参数的函数:容器本身。为了在外部调用它,你必须这样做:

$closure = function ($container) {
    var_dump($container);
};

$container = new Illuminate\Container\Container();
call_user_func($container->share($closure), $container);

原因在于服务定义的工作原理。 share的预期用途是包装服务定义。

像这样:

$container = new Illuminate\Container\Container();
$container['foo'] = $container->share(function ($container) { return new Foo(); });

当您访问服务时,如下所示:

var_dump($container['foo']);

它检查该值是否可调用,如果是,它将尝试将其作为函数调用。如果您不使用share,则每次都会获得一个新的Foo实例。 share会记住实例并每次都返回相同的实例。

要重新迭代,从$container返回的函数中的share参数就在那里,因为这就是服务创建的工作原理。服务定义(在容器上“设置”的“工厂”功能)只是一个接收容器并返回它正在创建的服务实例的函数。

由于offsetGet()期望定义采用$container参数,这就是share返回的内容。