预加载

从 PHP 7.4.0 开始,PHP 可以配置为在引擎启动时将脚本预加载到 opcache 中。这些文件中任何函数、类、接口或特性(但不包括常量)将随后对所有请求全局可用,无需显式包含。这以便利性和性能为代价(因为代码始终可用)来换取基本内存使用。它还需要重启 PHP 进程才能清除预加载的脚本,这意味着此功能仅适用于生产环境,不适用于开发环境。

请注意,性能和内存之间的最佳平衡可能因应用程序而异。“预加载所有内容”可能是最简单的策略,但不一定是最佳策略。此外,预加载只有在请求之间存在持久进程时才有用。这意味着虽然它可以在 opcache 启用的情况下在 CLI 脚本中工作,但通常没有意义。唯一的例外是在使用预加载的 FFI 库 时。

注意:

Windows 上不支持预加载。

配置预加载需要两个步骤,并要求 opcache 处于启用状态。首先,在 php.ini 中设置 opcache.preload

opcache.preload=preload.php

preload.php 是一个任意文件,它将在服务器启动时(PHP-FPM、mod_php 等)运行一次,并将代码加载到持久内存中。在作为 root 启动并在切换到非特权系统用户之前启动的服务器中,或者如果 PHP 将作为 root 运行(不建议),则 opcache.preload_user 值可以指定运行预加载的系统用户。默认情况下不允许以 root 身份运行预加载。设置 opcache.preload_user=root 以明确允许它。

preload.php 脚本中,由 includeinclude_oncerequirerequire_onceopcache_compile_file() 引用的任何文件都将被解析到持久内存中。在以下示例中,src 目录中的所有 .php 文件都将被预加载,除非它们是 Test 文件。

<?php
$directory
= new RecursiveDirectoryIterator(__DIR__ . '/src');
$fullTree = new RecursiveIteratorIterator($directory);
$phpFiles = new RegexIterator($fullTree, '/.+((?<!Test)+\.php$)/i', RecursiveRegexIterator::GET_MATCH);

foreach (
$phpFiles as $key => $file) {
require_once
$file[0];
}
?>

includeopcache_compile_file() 都可以使用,但对代码的处理方式有不同的影响。

  • include 将执行文件中的代码,而 opcache_compile_file() 不会。这意味着只有前者支持条件声明(在 if 块内声明的函数)。
  • 由于 include 将执行代码,因此嵌套的 included 文件也将被解析,其声明也会被预加载。
  • opcache_compile_file() 可以按任何顺序加载文件。也就是说,如果 a.php 定义了类 A,而 b.php 定义了扩展 A 的类 B,那么 opcache_compile_file() 可以按任何顺序加载这两个文件。但是,当使用 include 时,a.php 必须先包含。
  • 在任何情况下,如果后面的脚本包含一个已经预加载的文件,那么它的内容仍然会执行,但它定义的任何符号都不会被重新定义。使用 include_once 不会阻止文件第二次包含。可能需要再次加载文件才能包含在其中定义的全局常量,因为预加载不处理这些常量。
因此,哪种方法更好取决于所需的的行为。对于原本使用自动加载器的代码,opcache_compile_file() 允许更大的灵活性。对于原本手动加载的代码,include 将更健壮。

添加笔记

用户贡献笔记 2 条笔记

postmaster at greg0ire dot fr
1 年前
PHP 8.1 带有一个继承缓存,它与预加载的功能部分重叠。如果您在较低版本上启用了预加载,然后迁移到 PHP 8.1,您可能希望关闭预加载,看看这是否会带来性能损失。
postmaster at greg0ire dot fr
1 年前
启用预加载时有一些注意事项,其中之一是应该通过 php.ini 文件启用它。例如,通过 php-fpm 池配置启用它将不起作用,因为预加载是全局的,而不是按池的。为了确保您成功启用了预加载,您应该检查 opcache_get_status() 的输出中是否存在 preload_statistics 键。应该已经有一个 opcache_statistics 键,但这是完全不同的东西。
To Top