6.2. Lazy injection
延迟注入
不要将此功能与对象的延迟初始化混淆:PHP-DI总是仅在对象被请求或注入到对象时才创建对象。
延迟注入的作用远不止于此:它允许将对象依赖项的创建推迟到实际使用它们的那一刻,而不是之前。
警告:仅应在特殊情况下使用此功能,请阅读本页末尾的何时使用
示例
<?php
class ProductExporter
{
private $pdfWriter;
private $csvWriter;
public function __construct(PdfWriter $pdfWriter, CsvWriter $csvWriter)
{
$this->pdfWriter = $pdfWriter;
$this->csvWriter = $csvWriter;
}
public function exportToPdf()
{
$this->pdfWriter->write(...);
}
public function exportToCsv()
{
$this->csvWriter->write(...);
}
}
$productExporter = $container->get(ProductExporter::class);
$productExporter->exportToCsv();
在这个例子中, exportToPdf()
没有被调用。 PdfWriter
已初始化并注入到类中,但从未使用过。
如果PdfWriter
的初始化成本很高(例如,如果它有很多依赖性,或者如果它在构造函数中做了很多繁琐的事情),那么延迟注入可以帮你实现:直到它被使用才实例化对象。
如何工作
如果将对象定义为“延迟注入”,PHP-DI将注入:
- 对象(如果已创建)
- 或者,如果尚未创建的对象的代理,
代理是一种特殊的对象,其外观和行为与原始对象完全相同,因此您无法分辨出两者之间的区别。代理仅在需要时才实例化原始对象。
创建代理很复杂。为此,PHP-DI依赖于ProxyManager,这是一个非常棒的库,由Doctrine,Symfony和Zend开发。
让我们用一个例子来说明。简单起见,我们将不注入延迟对象,但将要求容器返回一个对象:
class Foo
{
public function doSomething()
{
}
}
$container->set('Foo', \DI\create()->lazy());
// $proxy 是一个代理对象,它没有初始化
// 轻量化内存
$proxy = $container->get('Foo');
var_dump($proxy instanceof Foo); // true
// 在代理上调用方法将对其进行初始化
$proxy->doSomething();
// 现在已初始化代理,已经创建并调用了Foo的真实实例
如何使用
您可以将一个对象定义为"延迟注入"。如果将其作为依赖项注入,则将代理替代注入。
安装
延迟注入依赖Ocramius/ProxyManager 库。 默认情况下,PHP-DI未安装该库,您需要安装它:
composer require ocramius/proxy-manager
配置
<?php
return [
'foo' => DI\create('MyClass')
->lazy(),
];
注解
/**
* @Injectable(lazy=true)
*/
class MyClass
{
}
PHP代码
<?php
$containerPHP->set('foo', \DI\create('MyClass')->lazy());
何时使用
延迟注入需要为声明为lazy
的每个对象创建代理对象。不建议在一个应用程序中多次使用此功能。
虽然代理经过了优化,但只有当您定义为延迟注入
的对象实例化(例如连接到数据库,写入文件等)时,它们才是有价值的。
性能优化
PHP-DI 需要生为您标记为"lazy "的类生成代理。
默认情况下,这些代理是在每个HTTP请求上生成的,这对开发有利,但对生产不利。
在生产中,应生成代理文件:
// 启用代理并将代理写入到文件并保存在tmp/proxies目录中
$containerBuilder->writeProxiesToFile(true, __DIR__ . '/tmp/proxies');
每次部署时,您都需要清除目录,以避免保留过时的代理。
编译容器时生成代理类
默认情况下,代理是在第一次使用时写入磁盘的。
可以通过启用容器编译预先生成代理类(例如,在部署之前):
// 在容器编译时将代理文件写到var/cache目录中
$containerBuilder->enableCompilation(__DIR__ . '/var/cache');
$containerBuilder->writeProxiesToFile(true, __DIR__ . '/var/cache');
为了使用此功能,必须同时设置两个配置选项。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。