darkghosthunter / preloader
从 Opcache 创建 PHP 准备好的预加载脚本的辅助工具。
Requires
- php: ^7.4||^8.0
- ext-json: *
- symfony/finder: ^4.3||^5.0.5
Requires (Dev)
- phpunit/phpunit: ^9.3
This package is auto-updated.
Last update: 2024-09-18 10:06:55 UTC
README
Opcache 预加载
通过一行代码获取最佳选项,以保持您的应用程序始终快速。
此包会自动从您的 Opcache 统计数据生成一个 PHP 预加载 脚本。无需手动修改。
如果您正在寻找预加载 Laravel 项目,请查看 Laragear 预加载。
目录
需求
- PHP 7.4.3, PHP 8.0 或更高版本。
- Opcache & 预加载已启用 (
ext-opcache
)。 - Composer 自动加载器(可选)。
安装
使用 Composer 在项目中要求此包
composer require darkghosthunter/preloader
此包安装不需要
ext-opcache
。只需确保它在您的应用程序服务器中已启用 (Opcache & 预加载已启用)。
使用
在应用程序的任何位置,只要 Opcache 已 启用 并运行,就可以调用 Preloader
并指定输出编译脚本的路径。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->writeTo(__DIR__.'/preloader.php');
这将自动收集 Opcache 统计数据,并写入一个优化的 preload.php
文件。在这种情况下,文件将创建在调用 Preloader 的同一目录中。
www
└── app
├── PreloaderCall.php
└── preload.php
一旦生成,请在启动时将此文件作为预加载器告诉 PHP 在 php.ini
中。
opcache.preload=/www/app/preload.php
一旦脚本生成,建议您重启 PHP 进程(或在某些情况下重启服务器)以获取生成的预加载脚本。仅生成脚本 是不够的。
如果您在 Opcache 禁用或没有命中时使用 Preloader,您将得到一个异常。
工作原理
此包仅请求 Opcache 的最常请求的文件,并从中编译一个列表。您可以在 Medium 上的这篇文章中检查有关此预加载的更多信息。
由于最好的统计数据是在您的应用程序运行一段时间后获得的,因此您可以使用自己的机制在满足某些条件后编译列表。
不用担心,您可以根据需要配置要编译的内容和方式。
配置
您可以配置 Preloader 在满足条件时运行,限制文件列表,以及其他事情。
条件
when()
此方法执行给定的可调用对象,并根据可调用对象返回的值评估是否应编译列表。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->when(fn () => $app->cache()->get('should_run'));
如果您可以将条件与自己的应用程序逻辑结合,例如给定数量的请求数或外部信号,则这很方便。
whenOneIn()
此方法是一个助手,允许您在给定的随机机会中快速生成 Preloader 脚本之一。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->whenOneIn(50);
例如,上述代码使得预加载器有五十分之一的机会生成编译列表。
列表
append()
您可以向编译列表中添加目录列表。它们内部的文件将被追加到编译列表中,不会考虑内存限制。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->append([ __DIR__ . '/files/*/more_files', __DIR__ . '/classes/' ]);
如果您添加的文件已经存在于编译列表中,这些文件将从不包含的文件中移除,以避免有效重复。
此软件包包含Symfony Finder,因此作为替代方案,您可以传递一个闭包,该闭包接收Finder实例以及您想要追加的文件。
<?php use Symfony\Component\Finder\Finder; use DarkGhostHunter\Preloader\Preloader; Preloader::make()->append(function (Finder $find) { $find->files()->in('/package')->name(['*.php', '*.twig']); });
exclude()
方法优先于append()
方法。如果您排除了一个后来被追加的文件,则不会排除它。
exclude()
此方法从Opcache列表中排除目录内的文件,这些文件最终会出现在预加载列表中。排除文件可能会释放编译列表的内存,为其他文件腾出空间。
您可以传递一个路径数组,如果您已经有一个准备好的排除列表,这会很有用。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->exclude([ __DIR__ . '/files/*/more_files', __DIR__ . '/vendor' ]);
此软件包包含Symfony Finder,因此作为替代方案,您可以传递一个闭包,该闭包接收Finder实例以及您想要排除的文件。
<?php use Symfony\Component\Finder\Finder; use DarkGhostHunter\Preloader\Preloader; Preloader::make()->exclude(function (Finder $find) { $find->files()->in('/package')->name(['*.php', '*.twig']); });
exclude()
方法优先于append()
方法。如果您排除了一个后来被追加的文件,则不会排除它。
selfExclude()
自动从预加载列表中排除软件包文件。
默认情况下,软件包不会被排除,因为它可能是请求最多的文件之一。只有在您完全确信在启用Opcache预加载的情况下它不会被调用时,才建议排除该软件包。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->selfExclude();
生成
memoryLimit()
默认情况下,预加载器默认内存限制为32MB,这对于大多数应用程序来说已经足够。预加载器将生成文件列表,直到达到该内存限制。
您可以使用MB
设置自己的内存限制。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->memoryLimit(32);
这考虑了Opcache中每个缓存的脚本的memory_consumption
键,而不是实际文件大小。
此限制与Opcache内存限制无关。
要禁用此限制,请使用memoryLimit(0)
。这将列出Opcache中的所有可用文件。
useRequire()
默认情况下,预加载器将使用opcache_compile_file()
将文件上传到Opcache。这避免了执行项目中的任何文件,但不会解析编译文件中的链接(特性、接口、扩展类等)。在预加载时,您可能会收到一些未解析链接的警告(没有太危险)。
您可以使用useRequire()
更改此设置,它将更改为require_once
,并沿着Composer自动加载器的路径(通常为vendor/autoload.php
)来解析链接。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->useRequire(__DIR__ . '/../vendor/autoload.php');
在编译具有未解析链接的文件时,您可能会收到一些警告。这些警告不是关键的,因为这些文件通常是在应用程序中最不常请求的。
ignoreNotFound()
某些应用程序可能在运行时创建文件,这些文件确实被Opcache缓存,但在应用程序首次部署时并不存在。
为了避免这个问题,您可以使用ignoreNotFound()
,它将编译一个脚本,该脚本忽略找不到或不可读的文件。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->ignoreNotFound();
如果文件可读,但预加载返回错误,它仍然会抛出异常。
编译
writeTo()
这将自动创建一个准备就绪的PHP脚本以预加载您的应用程序。如果条件满足,则返回true
,如果条件不满足,则返回false
。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->writeTo(__DIR__ . '/preloader.php');
您可以将false
作为第二个参数发出,以防止覆盖写路径中的任何现有文件。如果找到文件,则不会运行预加载逻辑。
getList()
您可以使用getList()
作为数组检索应包含的原始文件列表。
<?php use DarkGhostHunter\Preloader\Preloader; Preloader::make()->getList();
如果您有自己的脚本,或者只是想玩一下,这可能很有用。
安全预加载
此软件包附带了一个方便的安全预加载器,位于helpers/safe_preloader.php
。
它的功能非常简单:为PHP注册一个在预加载脚本完成后执行的下关机函数,并注册脚本可能返回的任何错误,以便您进行调试。
要使用它,将文件复制到PHP可访问的路径,并在真实的预加载脚本中,通过php.ini
引用它。
opcache.preload=/www/app/safe_preloader.php
<?php // /www/app/safe_preloader.php register_shutdown_function(function (): void { $error = error_get_last(); if (!$error) { return; } echo 'Preloader Script has stopped with an error:' . \PHP_EOL; echo 'Message: ' . $error['message'] . \PHP_EOL; echo 'File: ' . $error['file'] . \PHP_EOL; }); // require_once /* Path to your preload script */ require_once '/www/app/preloader.php';
从技术角度讲,Opcache在不同的进程中预加载文件,因此使用这个安全的预加载器不应有问题。
示例
好的。假设我们有一个包含数千个文件的代码库。我们不知道任何指标,所以如果请求在100次中有1次命中彩票,我们将以64MB的内存限制生成预加载脚本。
<?php // index.php use Framework\App; use DarkGhostHunter\Preloader\Preloader; require __DIR__ . '/../vendor/autoload.php'; $app = App::make(); $response = $app->run(); $response->sendToBrowser(); Preloader::make() ->whenOneIn(100) ->memoryLimit(64) ->writeTo(PHP_LOCALSTATEDIR . '/preload.php'); // put it in /var.;
安全
如果您发现任何与安全相关的问题,请通过电子邮件发送到darkghosthunter@gmail.com,而不是使用问题跟踪器。
许可证
MIT许可(MIT)。有关更多信息,请参阅许可文件。