mirror of
https://github.com/php/doc-zh.git
synced 2026-03-24 07:02:15 +01:00
116 lines
5.8 KiB
XML
116 lines
5.8 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- $Revision$ -->
|
||
<!-- EN-Revision: 87d6bb1bbd5f118f5b0cf0160438f06c0f91ea45 Maintainer: jhdxr Status: ready -->
|
||
<!-- CREDITS: Luffy -->
|
||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="opcache.preloading">
|
||
<title>预加载</title>
|
||
|
||
<simpara>
|
||
从 PHP 7.4.0 起,PHP 可以被配置为在引擎启动时将一些脚本预加载进 opcache 中。在那些文件中的任何函数、类、
|
||
接口或者 trait (但不包括常量)将在接下来的所有请求中变为全局可用,不再需要显示地包含它们。这牺牲了基准的
|
||
内存占用率但换来了方便和性能(因为这些代码将始终可用)。它还需要通过重启 PHP 进程来清除预加载的脚本,
|
||
这意味着这个功能仅在生产环境中有实用价值,而非开发环境。
|
||
</simpara>
|
||
|
||
<simpara>
|
||
需要注意的是,性能和内存之间的最佳平衡因应用而异。 “预加载一切” 可能是最简单的策略,但不一定是最好的策略。
|
||
此外,只有当不同的请求间有持久化的进程时,预加载才有用。这意味着,虽然在启用了 opcache 的命令行脚本中可以使用预加载,
|
||
但这通常是没有意义的。例外情况是在使用预加载时的 <link linkend="ffi.examples-complete">FFI 库</link>。
|
||
</simpara>
|
||
|
||
<note>
|
||
<simpara>
|
||
Windows 上不支持预加载。
|
||
</simpara>
|
||
</note>
|
||
|
||
<simpara>
|
||
配置预加载需要两步,并且要求开启 opcache。首先,在&php.ini; 中设置
|
||
<link linkend="ini.opcache.preload">opcache.preload</link> 的值:
|
||
</simpara>
|
||
|
||
<informalexample>
|
||
<programlisting role="ini">
|
||
<![CDATA[
|
||
opcache.preload=preload.php
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
|
||
<simpara>
|
||
<filename>preload.php</filename> 是一个在服务器启动时会运行一次(PHP-FPM、mod_php 等)的任意文件,
|
||
它的代码会加载到持久化内存中。在以 root 用户启动后切换到非特权系统用户的服务器上,又或者是以 root
|
||
用户身份运行 PHP 的情况(不建议这样做),可以通过<link linkend="ini.opcache.preload-user">opcache.preload_user</link>
|
||
来指定进行预加载的系统用户。
|
||
默认情况下,不允许以 root 用户身份进行预加载。通过设置 <literal>opcache.preload_user=root</literal> 来显示地允许它。
|
||
</simpara>
|
||
|
||
<simpara>
|
||
在 <filename>preload.php</filename> 脚本中, 任何被 <function>include</function>、
|
||
<function>include_once</function>、<function>require</function>、<function>require_once</function>或
|
||
<function>opcache_compile_file</function> 引用的文件将被解析到持久化内存中。 在下面的这个例子中,
|
||
所有在 <filename>src</filename> 目录下的 <filename class="extension">.php</filename> 文件将被预加载,除非那是一个
|
||
<literal>Test</literal> 文件。
|
||
</simpara>
|
||
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?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];
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
|
||
<para>
|
||
<function>include</function> 和 <function>opcache_compile_file</function> 都会生效,但对代码处理方式有不同的影响。
|
||
Both <function>include</function> and <function>opcache_compile_file</function> will work, but have different
|
||
implications for how code gets handled.
|
||
|
||
<itemizedlist>
|
||
<listitem><simpara><function>include</function> 将执行文件中的代码,而 <function>opcache_compile_file</function>
|
||
不会执行代码。这意味着只有前者支持条件声明(在 if 块中声明函数)。</simpara></listitem>
|
||
<listitem><simpara>由于 <function>include</function> 会执行代码,因此所有被 <function>include</function> 的文件也将被解析,
|
||
其中的定义也将被预加载。</simpara></listitem>
|
||
<listitem><simpara><function>opcache_compile_file</function> 可以按任何顺序加载文件。也就是说,如果 <filename>a.php</filename>
|
||
定义了类 <literal>A</literal>,而 <filename>b.php</filename> 定义了一个继承类 <literal>A</literal> 的类 <literal>B</literal>,
|
||
则 <function>opcache_compile_file</function> 可以按任何顺序来加载这两个文件。然而,当使用 <function>include</function> 时,
|
||
<filename>a.php</filename> <emphasis>必须</emphasis> 先被包含。</simpara></listitem>
|
||
<listitem><simpara>不管在哪种情况下,如果一个脚本包含了一个已经被预加载的文件,那么这个已经被预加载的文件里的内容仍将被执行,
|
||
但其中定义的任何符号将不会被重新定义。使用 <function>include_once</function> 不会阻止文件被二次包含。有时候可能仍需要重新加载文件
|
||
来包含其中定义的全局常量,因为这些常量预加载并不会处理。</simpara></listitem>
|
||
</itemizedlist>
|
||
|
||
因此,哪种方式更好取决于所需的行为。对于本来会使用自动加载器的代码,<function>opcache_compile_file</function>
|
||
有更高的灵活性。而对于本来会需要手动加载的代码,<function>include</function> 会更健壮。
|
||
</para>
|
||
|
||
</chapter>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|