1

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

但是我无法理解 3 段类似的代码。我将使用最小的片段来保持这个问题的清洁。

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

问题 1 问题 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;
        };
    } 

}

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

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 方法时遇到了同样的问题,它们都具有将不存在的参数作为闭包参数传​​递的相同实现,但我无法理解它是如何解析为容器实例本身的?

4

1 回答 1

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都会获得一个新实例。记忆实例并每次返回相同的实例Fooshare

再次重复,$container从函数返回的参数在share那里,因为这就是服务创建的工作方式。服务定义(您在容器上“设置”的“工厂”函数)只是一个接受容器并返回它正在创建的服务实例的函数。

由于offsetGet()它期望定义接受一个$container参数,这就是share返回的内容。

于 2013-08-12T15:14:20.690 回答