darkghosthunter/preloader

从 Opcache 创建 PHP 准备好的预加载脚本的辅助工具。

v2.2.0 2021-03-17 02:15 UTC

README

 Braden Collum - Unsplash (UL) #9HI8UJMSdZA

Latest Version on Packagist License Coverage Status

Opcache 预加载

通过一行代码获取最佳选项,以保持您的应用程序始终快速。

此包会自动从您的 Opcache 统计数据生成一个 PHP 预加载 脚本。无需手动修改。

如果您正在寻找预加载 Laravel 项目,请查看 Laragear 预加载

目录

需求

安装

使用 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)。有关更多信息,请参阅许可文件