diego-ninja / preloader
从 Opcache 创建 PHP 准备的预加载脚本的辅助工具。
Requires
- php: ^8.1
- symfony/finder: ^6 || ^7
Requires (Dev)
- captainhook/captainhook: ^5.10
- captainhook/plugin-composer: ^5.3
- dealerdirect/phpcodesniffer-composer-installer: ^0.7
- ergebnis/composer-normalize: ^2.30
- friendsofphp/php-cs-fixer: ^3.40
- icanhazstring/composer-unused: ^0.8.7
- maglnet/composer-require-checker: ^4.5
- php-parallel-lint/php-console-highlighter: ^1.0
- php-parallel-lint/php-parallel-lint: ^1.3
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.3
- phpunit/phpunit: ^10
- roave/security-advisories: dev-latest
This package is auto-updated.
Last update: 2024-09-15 20:05:22 UTC
README
Opcache 预加载
只需一行代码即可获得最佳选项,以保持您的应用程序始终保持高速。
此包会自动从您的 Opcache 统计信息生成一个PHP 预加载脚本。无需手动更改。此包是darkghosthunter/preloader的分支,目标仅为更新代码和依赖项以适应 php 8.x 和 Symfony 6 组件。目前,它不添加新功能。
如果您需要 php 7.4 支持,请使用上述包。
如果您正在寻找预加载 Laravel 项目,请查看Laragear PReload。
目录
要求
- PHP 8.1 或更高版本。
- Opcache & 预加载已启用 (
ext-opcache
). - Composer 自动加载(可选)。
安装
使用 Composer 在您的项目中引入此依赖项
composer require diego-ninja/preloader
此包安装不需要
ext-opcache
。只需确保它在您的应用程序服务器中已启用。
用法
在您的应用程序中任何 Opcache 已启用并运行的地方,调用 Preloader
并指定输出编译脚本的路径
<?php use Ninja\Preloader\Preloader; Preloader::make()->writeTo(__DIR__.'/preloader.php');
这将自动收集 Opcache 统计信息,并写入优化的 preload.php
文件。在这种情况下,文件将在调用 Preloader 的同一目录中创建。
www
└── app
├── PreloaderCall.php
└── preload.php
一旦生成,请在启动时将此文件指定为预加载文件 php.ini
。
opcache.preload=/www/app/preload.php
一旦脚本生成,建议您重新启动 PHP 进程(或在某些情况下重启服务器)以获取生成的预加载脚本。仅生成脚本是不够的。
如果您在 Opcache 禁用或无命中时使用 Preloader,您将得到一个异常。
工作原理
此包仅请求 Opcache 中最常请求的文件,并根据这些文件编译列表。您可以在Medium 上的这篇文章中了解更多关于该预加载的信息。
由于最好的统计数据是在您的应用程序运行一段时间后获得的,因此您可以使用自己的机制在满足某些条件后才编译列表。
请放心,您可以配置要编译什么以及如何编译列表。
配置
您可以配置 Preloader 在满足条件时运行,限制文件列表,以及其他事情。
条件
when()
此方法执行给定的可调用函数,并根据可调用函数返回的值判断是否应该编译列表。
<?php use Ninja\Preloader\Preloader; Preloader::make()->when(fn () => $app->cache()->get('should_run'));
如果您可以将条件与您自己的应用程序逻辑结合,例如给定数量的请求或外部信号,这将非常有用。
whenOneIn()
此方法只是一个辅助工具,允许您以一定的随机概率快速生成一个预加载脚本。
<?php use Ninja\Preloader\Preloader; Preloader::make()->whenOneIn(50);
例如,上述代码使预加载脚本有五十分之一的机会生成一个编译列表。
列表
append()
您可以将目录列表添加到编译列表中。这些目录内的文件将被追加到编译列表中,不会考虑内存限制。
<?php use Ninja\Preloader\Preloader; Preloader::make()->append([ __DIR__ . '/files/*/more_files', __DIR__ . '/classes/' ]);
如果您添加的文件已经存在于编译列表中,这些文件将不会被包含,以避免有效的重复。
本包包含Symfony Finder,因此作为替代方案,您可以传递一个闭包,该闭包接收Finder实例以及您想要追加的文件。
<?php use Symfony\Component\Finder\Finder; use Ninja\Preloader\Preloader; Preloader::make()->append(function (Finder $find) { $find->files()->in('/package')->name(['*.php', '*.twig']); });
exclude()
方法优先于append()
。如果您排除了一个后来被追加的文件,则它不会被排除。
exclude()
此方法从Opcache列表中排除目录内的文件,这些文件最终会出现在预加载列表中。排除文件可能会释放编译列表的内存,为其他文件腾出空间。
您可以传递一个路径数组,如果您已经准备好要排除的列表,这是一个好方法。
<?php use Ninja\Preloader\Preloader; Preloader::make()->exclude([ __DIR__ . '/files/*/more_files', __DIR__ . '/vendor' ]);
本包包含Symfony Finder,因此作为替代方案,您可以传递一个闭包,该闭包接收Finder实例以及您想要排除的文件。
<?php use Symfony\Component\Finder\Finder; use Ninja\Preloader\Preloader; Preloader::make()->exclude(function (Finder $find) { $find->files()->in('/package')->name(['*.php', '*.twig']); });
exclude()
方法优先于append()
。如果您排除了一个后来被追加的文件,则它不会被排除。
selfExclude()
自动排除包文件从预加载列表。
默认情况下,该包不被排除,因为它可能是最请求的文件之一。只有在您完全确信一旦启用Opcache预加载它不会被调用时,才建议排除该包。
<?php use Ninja\Preloader\Preloader; Preloader::make()->selfExclude();
生成
memoryLimit()
默认情况下,预加载器默认的内存限制为32MB,这对于大多数应用程序来说足够了。预加载器将生成一个文件列表,直到达到内存限制。
您可以在MB中设置自己的内存限制。
<?php use Ninja\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 Ninja\Preloader\Preloader; Preloader::make()->useRequire(__DIR__ . '/../vendor/autoload.php');
在编译具有未解决链接的文件时,您可能会收到一些警告。这些不是关键警告,因为这些文件通常是应用程序中最少请求的。
ignoreNotFound()
一些应用程序可能会在运行时创建文件,这些文件确实被Opcache缓存,但在应用程序首次部署时并不存在。
为了避免这个问题,您可以使用ignoreNotFound()
,它将编译一个脚本,该脚本忽略找不到的文件或不可读的文件。
<?php use Ninja\Preloader\Preloader; Preloader::make()->ignoreNotFound();
如果文件可读,但预加载返回错误,它仍将抛出异常。
编译
writeTo()
这将自动创建一个用于预加载应用程序的PHP脚本。如果成功,它将返回true
,如果条件不满足,则返回false
。
<?php use Ninja\Preloader\Preloader; Preloader::make()->writeTo(__DIR__ . '/preloader.php');
您可以将false
作为第二个参数传递,以防止覆盖写入路径中任何现有的文件。如果找到文件,则不会运行预加载逻辑。
getList()
您可以使用getList()
使用户能够以数组的形式检索应包含的原始文件列表。
<?php use Ninja\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在不同的进程中预加载文件,因此使用这个安全预加载器不应该有问题。
示例
好的。假设我们有一个包含数千个文件的代码库。我们不知道任何指标,所以当请求击中1/100的彩票时,我们将生成一个预加载脚本,内存限制为64MB。
<?php // index.php use Framework\App; use Ninja\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.;
安全
如果您发现任何与安全相关的问题,请通过电子邮件发送到yosoy@diego.ninja,而不是使用问题跟踪器。
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。