TLDR 这是因为将依赖项定义为闭包使得依赖注入容器可以按需构建它们,因此您无需担心它们的定义顺序和手动管理它们的依赖项。
Pimple 是Dependency Injection Container,它应该可以通过简单方便的方式管理对象的依赖关系来帮助您设置对象。
如果您直接为键分配值,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 在缓存上应用相同的东西,如果它还没有构建,它会构建它等等......直到它到达需要像db-config 这样的简单参数的部分,它将立即返回。在这个闭包调用链中,我们的对象及其所有依赖项都被构建了。
现在想象一下,如果我们使用简单的值而不是闭包会发生什么?在这种情况下,当我们想要构建 myService 我们 必须处理它的依赖关系。我们必须确保在定义服务本身之前定义它的依赖关系,并且我们必须处理与管理依赖关系相关的其他问题。在那种情况下,我们不能只定义我们的myService 并且假设有一个cache 服务可用,稍后将定义。