PHP 8.1 附帶了一個繼承快取,它與預先載入的功能部分重疊。如果您在較低版本上啟用了預先載入,然後遷移到 PHP 8.1,您可能需要關閉預先載入,看看是否會導致效能下降。
自 PHP 7.4.0 起,可以將 PHP 設定為在引擎啟動時將腳本預先載入到 opcache 中。這些檔案中的任何函式、類別、介面或特性(但不包括常數)將會全域可用於所有請求,而無需明確地 include 它們。這以方便性和效能(因為程式碼始終可用)來換取基準記憶體使用量。它還需要重新啟動 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 腳本中,任何被 include、include_once、require、require_once 或 opcache_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];
}
?>
include 和 opcache_compile_file() 都可以使用,但它們對程式碼處理方式的影響不同。
A
,而 b.php 定義了繼承自 A
的類別 B
,那麼 opcache_compile_file() 可以以任何順序載入這兩個檔案。然而,當使用 include 時,a.php 必須 先被載入。PHP 8.1 附帶了一個繼承快取,它與預先載入的功能部分重疊。如果您在較低版本上啟用了預先載入,然後遷移到 PHP 8.1,您可能需要關閉預先載入,看看是否會導致效能下降。
啟用預先載入有一些注意事項,其中之一是它應該透過 php.ini 檔案啟用。例如,使用 php-fpm 池組態啟用它將無法運作,因為預先載入是全域的,而不是每個池的。為了確保您已成功啟用預先載入,您應該在 opcache_get_status() 的輸出中檢查 preload_statistics 鍵值。應該已經有一個 opcache_statistics 鍵值,但那是完全不同的東西。