我正在观看this video,并且在7:10他正在添加数据库依赖项,并使用闭包来分配值。
我的问题是为什么不直接使用直接分配,我的意思是不这样做:
$container['db'] = $capsule;
相当于这样做:
$container['db'] = function ($container) use ($capsule) {
return $capsule;
}
如果没有,有什么区别,哪种方式更好?
答案 0 :(得分:2)
TLDR 它因为将依赖关系定义为闭包使得依赖注入容器可以按需构建它们,因此您不必担心它们的定义顺序和手动管理他们的依赖。
Pimple是依赖注入容器,它应该通过简单方便的方式管理其依赖项来帮助您设置对象。
如果直接为某个键指定值,则Pimple将该值称为参数,当您需要访问该键时,它只返回该确切值:
$container['sample-param'] = 'foo';
echo $container['sample-param'];
//output: foo
但重点是,这个sample-param
不需要任何设置,它只是一个值,我们对此很好。但假设以下服务设置:
$container['myService'] = function($c) {
$service = new \Some\Complicated\Service();
//this service depends on cache service
$service->setCache($c['cache']);
return $service;
}
$container['cache'] = function($c) {
$cache = new \Cache\Driver();
//our cache driver needs a db connection
$cache->setDbConnection($c['db']);
return $cache;
}
$container['db'] = function($c) {
//our database connection requires some parameters
$dbConnection = new \Database\Connection($c['db-config']);
return $dbConnection;
}
$container['db-config'] = [
'username' => 'foo',
'password' => 'bar',
'host' => 'localhost'
];
//Now we want to user our service:
$container['myService']->doSomething();
请注意我用来定义容器中不同键的顺序。
myService
需要cache
,但缓存定义位于myService定义之后。这就是Pimple正在帮助的地方,这就是我们将容器传递给每个闭包的原因,因为Pimple将根据需要构建我们的依赖。当我们需要访问myService
时,Pimple查看其内部数据存储,如果它先前已成功构建并存储myService
,它将返回相同的实例,否则它将调用我们的闭包来构建它。当调用我们的闭包时,它会询问Pimple($ c是Pimple容器)给它 dependecies (在这种情况下是cache
服务)。 Pimple在缓存上应用相同的东西,如果它还没有构建,它将构建它等等......直到它到达需要简单的params的部分,如db-config
将立即返回。在这个闭包调用链中,构建了我们的对象及其所有依赖项。
现在想象如果我们使用简单的值而不是闭包会发生什么?在这种情况下,当我们想构建myService
时,我们必须处理它的依赖关系。我们必须确保其依赖关系定义之前我们定义服务本身,而我们必须处理与管理依赖关系相关的其他问题。在这种情况下,我们无法定义我们的myService
和假设有一个cache
服务可用,稍后会定义。
答案 1 :(得分:0)
在该视频中,他使用Slim框架作为容器,默认情况下使用Pimple作为容器。
在该页面的文档中,它提到了以下内容
定义服务服务是一个作为一部分做某事的对象 一个更大的系统。服务示例:数据库连接,a 模板引擎或邮件程序。几乎任何全局对象都可以是 服务。
服务由返回实例的匿名函数定义 一个对象:
// define some services $container['session_storage'] = function ($container) { return new SessionStorage('SESSION_ID'); }; $container['session'] = function ($container) { return new Session($container['session_storage']); };
请注意,匿名函数可以访问当前容器实例,允许引用其他服务或参数。
按设计,容器期望调用函数
Pimple的容器实现\ArrayAccess
接口(seen here),这意味着它们可以使对象像一个数组,而不一定是一个。在源代码中,您会注意到offsetSet
和offsetGet
,这是您执行此操作时发生的情况:
$container['a'] = function($c){ return new Blah();}
$thing = $container['a'];
tl; dr 这是一个特定于Pimple容器的东西,而不是特定于PHP的东西。
答案 2 :(得分:-1)
它完全不同。第一个$container['db'] = $capsule;
表示$container
数组具有db
键且该键等于$capsule
,
第二个意味着你有一个$container
数组,db
键有值闭包。转储两个结果时可以看到区别:
关闭示例:
$capsule = 1;
$container['db'] = function ($container) use ($capsule) {
return $capsule;
};
var_dump($container);
结果:
Array(1) {
["db"]=>
object(Closure)#1 (2) {
["static"]=>
array(1) {
["capsule"]=>
int(1)
}
["parameter"]=>
array(1) {
["$container"]=>
string(10) "<required>"
}
}
}
非封闭示例:
$capsule = 1;
$container['db'] = $capsule;
var_dump($container);
结果:
result array(1) {
["db"]=>
int(1)
}
您可以在php手册中阅读有关闭包的内容,以便更好地了解其角色。 PHP Closures Manual