我一直在研究laravel 4容器,以获得更多关于laravel内部的知识,并提高我自己编写更好代码的技能。
然而,我无法理解3个相似的代码片段。 我将使用最小的片段来保持这个问题的清洁。
类似的问题可以在下面的链接中找到。虽然人们回答了正确的答案,但我不满足于简单地“知道如何使用它,但不知道它是如何工作的”。所以我真的希望有人可以解释这一切。
<?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>
答案 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
返回的内容。