6.1. Performances

未匹配的标注

性能

关于缓存的注意事项

PHP-DI 4和5非常依赖缓存。现在,PHP-DI 6的主要优化方法是将容器编译为高度优化的代码(请参见下文)。编译容器更加简单快捷。

编译容器

PHP-DI 会执行两项很繁琐的任务:

为了避免执行这两项任务,可以将容器编译为针对您的配置和类进行了优化的PHP代码。

配置

配置编译容器很简单,只需要在容器构建器上调用 enableCompilation() 方法:

$containerBuilder = new \DI\ContainerBuilder();
$containerBuilder->enableCompilation(__DIR__ . '/var/cache');

// […]

$container = $containerBuilder->build();

enableCompilation() 方法需要传入保存编译容器的目录路径。

在生产环境中部署

将容器配置为可编译时,它只会被编译一次,并且永远不会再次生成。这样可以最大限度地提高生产性能。

当您将新版本的代码部署到生产环境时, 必须删除编译生成的文件 (或者删除整个目录) 以确保重新编译容器

如果您的产品流量很大, 那么您可能还想在新版本的代码 发布之前 生成编译容器。该阶段称为“预编译”。为此,只需在部署步骤中构建容器(调用$ containerBuilder-> build()),即可创建好编译容器。

开发环境

请勿在开发环境中配置编译容器,否则您对定义所做的所有更改(注解,配置文件等)将不会生效。你可以这样做:

$containerBuilder = new \DI\ContainerBuilder();
if (/* 如果是生产环境 */) {
    $containerBuilder->enableCompilation(__DIR__ . '/var/cache');
}

优化编译

正如PHP-DI 如何工作 部分中所讲, PHP-DI 会在配置中找到并编译所有的定义。这意味着不在配置列表的自动装配类将不会被编译 ,因为PHP-DI不知道它们的存在。

如果要最大程度地优化性能,可以通过在定义文件中列出所有自动装配的类,使PHP-DI知道它们的存在:

return [
    // ... (你的 definitions)

    UserController::class => autowire(),
    BlogController::class => autowire(),
    ProductController::class => autowire(),
    // ...
];

您不需要具体配置它们 (自动装配会帮你解决),但至少现在PHP-DI会知道这些类并编译它们。

当前,PHP-DI不会遍历目录以自动查找自动装配或包含注解的类。

它也不会在编译过程中解析 通配符 。即使定义仍然可以正常地工作,但使用编译容器时根本不会提高它们的性能。

另一方面,在编译容器中支持工厂定义(使用闭包或类工厂定义)。但是请注意,如果您将闭包用作工厂:

  • 您不应在闭包内使用$ this
  • 您不应使用use关键字在闭包内部导入变量,例如在function()use($ foo){...

存在这些限制是因为每个闭包的代码都被复制到已编译的容器中。可以肯定地说,即使不编译容器,你也不应该执行这些操作。

如何工作

PHP-DI将从您的 配置中读取定义。 编译容器时,将根据这些定义生成PHP代码。

例如,我们定义创建对象的定义:

return [
    'Logger' => DI\create()
        ->constructor('/tmp/app.log')
        ->method('setLevel', 'warning'),
];

该定义将被编译为类似于以下代码的PHP代码:

$object = new Logger('/tmp/app.log');
$object->setLevel('warning');
return $object;

所有已编译的定义都将存储到一个PHP类(已编译的容器)中,该类会被写入到文件(例如CompiledContainer.php)中。

在运行时,容器构建器发现CompiledContainer.php存在,并进行加载(而不是加载定义文件)。该PHP文件可能包含很多代码,但是PHP的opcode cache会将此类存储在内存中(请记住在生产环境中使用opcache)。当需要解析定义时,PHP-DI将仅执行已编译的代码并返回创建的实例。

优化延迟注入

如果您使用的是 延迟注入 功能 则应阅读它的 "优化性能"指南.

缓存

编译容器是最有效的解决方案,但是有一些限制。以下情况未优化:

  • 在配置中未声明的自动装配 (或注解) 类
  • 通配符定义
  • 使用 Container::make() 或者 Container::injectOn() (因为它们未使用编译代码)

如果您大量使用这些功能,并且如果使应用程序变慢,则可以启用缓存系统。缓存将确保在每个请求上都不会再次读取注解或反射。

缓存直接依赖于APCu,因为它是唯一有意义的缓存系统(读写速度非常快)。其他缓存不是很好的选择,这就是为什么PHP-DI不为此缓存使用PSR-6或PSR-16的原因。

要启用缓存:

$containerBuilder = new \DI\ContainerBuilder();
if (/* 如果是生产环境 */) {
    $containerBuilder->enableDefinitionCache();
}

小心:

  • 不要在开发环境中使用缓存,否则您对定义(注解,配置文件等)所做的更改将不会生效
  • 在生产环境的每个部署上清除APCu缓存(以避免使用陈旧的缓存)

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/php-di/6.0/perf...

译文地址:https://learnku.com/docs/php-di/6.0/perf...

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~