为什么要用闭包来赋值,而不是直接给键赋值呢?
Why use a closure for assignment instead of directly assigning a value to a key?
我在看 this video 并且在 7:10 他正在添加数据库依赖项并使用闭包来分配值。
我的问题是为什么不直接使用直接赋值,我的意思是不这样做:
$container['db'] = $capsule;
相当于这样做:
$container['db'] = function ($container) use ($capsule) {
return $capsule;
}
如果不是,有什么区别,哪种方式更好?
在该视频中,他使用 Slim 框架作为容器,默认情况下使用 Pimple 作为容器。
在该页面的文档中提到了以下内容
Defining Services A service is an object that does something as part
of a larger system. Examples of services: a database connection, a
templating engine, or a mailer. Almost any global object can be a
service.
Services are defined by anonymous functions that return an instance of
an object:
// define some services
$container['session_storage'] = function ($container) {
return new SessionStorage('SESSION_ID');
};
$container['session'] = function ($container) {
return new Session($container['session_storage']);
};
Notice that the anonymous function has access to the current container instance, allowing references to other services or parameters.
根据设计,容器期望调用一个函数
Pimple 的容器实现了 \ArrayAccess
接口 (seen here),这意味着它们可以使对象像数组一样工作,但不一定是一个。在源代码中,您会注意到 offsetSet
和 offsetGet
,这是您执行以下操作时发生的情况:
$container['a'] = function($c){ return new Blah();}
$thing = $container['a'];
tl;dr 这是 Pimple 容器特定的东西,而不是 PHP 特定的东西。
TLDR 这是因为将依赖定义为闭包使得依赖注入容器可以按需构建它们,因此您无需担心它们的定义和管理顺序手动依赖它们。
Pimple 是依赖注入容器,它应该可以帮助您通过以简单方便的方式管理对象的依赖关系来设置对象。
如果您直接为键分配一个值,Pimple 将该值称为 参数,当您需要访问该键时,它只是 return精确值:
$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
,它将 return 同一个实例,否则它将调用我们的闭包建造它。当我们的闭包被调用时,它会要求 Pimple($c 是 Pimple 容器)给它 dependecies(在本例中是 cache
服务)。 Pimple 在缓存上应用相同的东西,如果尚未构建,它将构建它,依此类推......直到它到达需要简单参数的部分,如 db-config
,它将立即 return。在这个闭包调用链中,我们的对象及其所有依赖项都已构建。
现在想象一下如果我们使用简单的值而不是闭包会发生什么?在那种情况下,当我们想要构建 myService
时,我们 必须处理它的依赖关系。我们必须确保在定义服务本身之前 定义了它的依赖项 ,并且 我们 必须处理与管理依赖项相关的其他问题。在那种情况下,我们不能只定义我们的 myService
和 假设 有一个可用的 cache
服务,稍后将定义它。
我在看 this video 并且在 7:10 他正在添加数据库依赖项并使用闭包来分配值。
我的问题是为什么不直接使用直接赋值,我的意思是不这样做:
$container['db'] = $capsule;
相当于这样做:
$container['db'] = function ($container) use ($capsule) {
return $capsule;
}
如果不是,有什么区别,哪种方式更好?
在该视频中,他使用 Slim 框架作为容器,默认情况下使用 Pimple 作为容器。
在该页面的文档中提到了以下内容
Defining Services A service is an object that does something as part of a larger system. Examples of services: a database connection, a templating engine, or a mailer. Almost any global object can be a service.
Services are defined by anonymous functions that return an instance of an object:
// define some services $container['session_storage'] = function ($container) { return new SessionStorage('SESSION_ID'); }; $container['session'] = function ($container) { return new Session($container['session_storage']); };
Notice that the anonymous function has access to the current container instance, allowing references to other services or parameters.
根据设计,容器期望调用一个函数
Pimple 的容器实现了 \ArrayAccess
接口 (seen here),这意味着它们可以使对象像数组一样工作,但不一定是一个。在源代码中,您会注意到 offsetSet
和 offsetGet
,这是您执行以下操作时发生的情况:
$container['a'] = function($c){ return new Blah();}
$thing = $container['a'];
tl;dr 这是 Pimple 容器特定的东西,而不是 PHP 特定的东西。
TLDR 这是因为将依赖定义为闭包使得依赖注入容器可以按需构建它们,因此您无需担心它们的定义和管理顺序手动依赖它们。
Pimple 是依赖注入容器,它应该可以帮助您通过以简单方便的方式管理对象的依赖关系来设置对象。
如果您直接为键分配一个值,Pimple 将该值称为 参数,当您需要访问该键时,它只是 return精确值:
$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
,它将 return 同一个实例,否则它将调用我们的闭包建造它。当我们的闭包被调用时,它会要求 Pimple($c 是 Pimple 容器)给它 dependecies(在本例中是 cache
服务)。 Pimple 在缓存上应用相同的东西,如果尚未构建,它将构建它,依此类推......直到它到达需要简单参数的部分,如 db-config
,它将立即 return。在这个闭包调用链中,我们的对象及其所有依赖项都已构建。
现在想象一下如果我们使用简单的值而不是闭包会发生什么?在那种情况下,当我们想要构建 myService
时,我们 必须处理它的依赖关系。我们必须确保在定义服务本身之前 定义了它的依赖项 ,并且 我们 必须处理与管理依赖项相关的其他问题。在那种情况下,我们不能只定义我们的 myService
和 假设 有一个可用的 cache
服务,稍后将定义它。