{"id":15030262,"url":"https://github.com/diego-ninja/preloader","last_synced_at":"2025-10-04T01:30:51.913Z","repository":{"id":42391813,"uuid":"478878908","full_name":"diego-ninja/preloader","owner":"diego-ninja","description":"Preloader helper to create a PHP-ready preload script from Opcache.","archived":false,"fork":true,"pushed_at":"2024-01-15T18:34:45.000Z","size":128,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2024-12-29T06:18:33.291Z","etag":null,"topics":["satis-enabled"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"DarkGhostHunter/Preloader","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diego-ninja.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"ko_fi":"DarkGhostHunter","custom":["https://paypal.me/darkghosthunter"]}},"created_at":"2022-04-07T07:44:12.000Z","updated_at":"2024-07-01T15:04:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/diego-ninja/preloader","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diego-ninja%2Fpreloader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diego-ninja%2Fpreloader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diego-ninja%2Fpreloader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diego-ninja%2Fpreloader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diego-ninja","download_url":"https://codeload.github.com/diego-ninja/preloader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235208940,"owners_count":18953003,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["satis-enabled"],"created_at":"2024-09-24T20:12:55.151Z","updated_at":"2025-10-04T01:30:51.588Z","avatar_url":"https://github.com/diego-ninja.png","language":"PHP","funding_links":["https://ko-fi.com/DarkGhostHunter","https://paypal.me/darkghosthunter"],"categories":[],"sub_categories":[],"readme":"![\nBraden Collum - Unsplash (UL) #9HI8UJMSdZA](https://images.unsplash.com/photo-1461896836934-ffe607ba8211?ixlib=rb-1.2.1\u0026ixid=eyJhcHBfaWQiOjEyMDd9\u0026auto=format\u0026fit=crop\u0026w=1280\u0026h=400\u0026q=80)\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/diego-ninja/preloader.svg?style=flat)](https://packagist.org/packages/diego-ninja/preloader)\n[![Total Downloads](https://img.shields.io/packagist/dt/diego-ninja/preloader.svg?style=flat\u0026color=blue)](https://packagist.org/packages/diego-ninja/preloader)\n![PHP Version](https://img.shields.io/packagist/php-v/diego-ninja/preloader.svg?style=flat)\n[![License](https://poser.pugx.org/diego-ninja/preloader/license)](https://packagist.org/packages/darkghosthunter/preloader)\n ![Composer](https://github.com/diego-ninja/Preloader/workflows/PHP%20Composer/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/diego-ninja/Preloader/badge.svg?branch=master)](https://coveralls.io/github/diego-ninja/Preloader?branch=master)\n[![PHPStan Level 8](https://img.shields.io/badge/PHPStan-level%208-blue.svg)](https://github.com/diego-ninja/preloader/blob/main/.github/workflows/static-code-analysis.yml)\n\n# Opcache Preloader\n\nGet the best options to keep your application fast as ever, with just one line.\n\nThis package generates a [PHP preloading](https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload) script from your Opcache statistics automatically. No need to hack your way in. This package is a fork of\n[darkghosthunter/preloader](https://github.com/DarkGhostHunter/Preloader) with the only target of update code and dependencies to fit with php 8.x and Symfony 6 components. It doesn't add, at least at the moment, new functionality.\n\nIf you need php 7.4 support please, use the aforementioned package.\n\n\u003e If you're looking for preloading your Laravel project, check [Laragear PReload](https://github.com/Laragear/Preload).\n\n## Table of Contents\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Usage](#usage)\n- [How it works](#how-it-works)\n- [Configuration](#configuration)\n  * [Conditions](#conditions)\n    + [`when()`](#when)\n    + [`whenOneIn()`](#whenOneIn)\n  * [Listing](#listing)\n    + [`append()`](#append)\n    + [`exclude()`](#exclude)\n    + [`selfExclude()`](#selfexclude)\n  * [Generation](#generation)\n    + [`memoryLimit()`](#memorylimit)\n    + [`useRequire()`](#userequire)\n    + [`ignoreNotFound()`](#ignorenotfound)\n  * [Compilation](#compilation)\n    + [`writeTo()`](#writeto)\n    + [`getList()`](#getlist)\n- [Safe Preloader](#safe-preloader)\n- [Example](#example)\n- [Security](#security)\n- [License](#license)\n\n## Requirements\n\n* PHP 8.1 or later.\n* [Opcache \u0026 Preloading enabled](https://www.php.net/manual/en/book.opcache.php) (`ext-opcache`).\n* Composer Autoloader (optional).\n\n## Installation\n\nRequire this using Composer into your project\n\n    composer require diego-ninja/preloader\n\n\u003e This package doesn't require `ext-opcache` to install. Just be sure to have it [enabled in your application server](https://www.php.net/manual/en/book.opcache.php).\n\n## Usage\n\nAnywhere in your application, where Opcache is **enabled** and running, call `Preloader` with where to output the compiled script:\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003ewriteTo(__DIR__.'/preloader.php');\n```\n\nThis will automatically gather Opcache statistics, and write an optimized `preload.php` file. In this case, the file will be created in the same directory the Preloader was called.\n\n    www\n    └── app\n        ├── PreloaderCall.php\n        └── preload.php\n\nOnce generated, tell PHP to use this file as a preloader at start up in your `php.ini`.\n\n```ini\nopcache.preload=/www/app/preload.php\n```\n\nOnce the script is generated, **you're encouraged to restart your PHP process** (or server, in some cases) to pick up the generated preload script. Only generating the script [is not enough](https://www.php.net/manual/en/opcache.preloading.php).\n\n\u003e If you use Preloader when Opcache is disabled or without hits, you will get an Exception.\n\n## How it works\n\nThis package asks Opcache only for the most requested files and compiles a list from it. You can [check this article in Medium about that preload](https://medium.com/p/9ede756f292c/).\n\nSince the best statistics are those you get **after** your application has been running for a while, you can use your own mechanisms to compile the list only after certain conditions are met.\n\n![](https://miro.medium.com/max/1365/1*Zp-rR9-dPNn55L8GjSUpJg.png)\n\nDon't worry, you can configure what and how compile the list.\n\n## Configuration\n\nYou can configure the Preloader to run when a condition is met, limit the file list, among what other things.\n\n### Conditions\n\n#### `when()`\n\nThis method executes the given callable and checks if the preloader should compile the list or not based on what the callable returning value evaluates.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003ewhen(fn () =\u003e $app-\u003ecache()-\u003eget('should_run'));\n```\n\nThis is handy if you can combine the condition with your own application logic, like a given number of requests, or an external signal.\n\n#### `whenOneIn()`\n\nThis is method is just a helper to allows you to quickly generate a Preloader script in one of a given number of random chances.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003ewhenOneIn(50);\n```\n\nFor example, the above makes the Preloader generate a compiled list one in fifty chances.\n\n### Listing\n\n#### `append()`\n\nYou can add a list of directories to the compiled list. The files inside them will be appended to the compiled list, and won't account for memory restrictions.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003eappend([\n    __DIR__ . '/files/*/more_files', \n    __DIR__ . '/classes/'\n]);\n```\n\n\u003e If the files you're adding are already in the compiled list, these will be removed from the included files to avoid effective duplicates.\n\nThis packages includes [Symfony Finder](https://symfony.com/doc/current/components/finder.html), so as an alternative you can pass a closure that receives the Finder instance along with the files you want to append.\n\n```php\n\u003c?php\n\nuse Symfony\\Component\\Finder\\Finder;\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003eappend(function (Finder $find) {\n    $find-\u003efiles()-\u003ein('/package')-\u003ename(['*.php', '*.twig']);\n});\n```\n\n\u003e The `exclude()` method take precedence over `append()`. If you exclude a file that is later appended, you won't exclude it at all.\n\n#### `exclude()`\n\nThis method excludes files from inside directories from Opcache list, which later end up in the Preload list. Excluding files may free up the memory of the compiled list, leaving space for others to be included.\n\nYou can pass an array of paths, which is good if you already have a list ready to exclude.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003eexclude([\n    __DIR__ . '/files/*/more_files',\n    __DIR__ . '/vendor'\n]);\n```\n\nThis packages includes [Symfony Finder](https://symfony.com/doc/current/components/finder.html), so as an alternative you can pass a Closure receiving the Finder instance along with the files you want to exclude.\n\n```php\n\u003c?php\n\nuse Symfony\\Component\\Finder\\Finder;\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003eexclude(function (Finder $find) {\n    $find-\u003efiles()-\u003ein('/package')-\u003ename(['*.php', '*.twig']);\n});\n```\n\n\u003e The `exclude()` method take precedence over `append()`. If you exclude a file that is later appended, you won't exclude it at all.\n\n#### `selfExclude()`\n\nAutomatically excludes the Package files from the Preload list.\n\nBy default, the package is not excluded, since it may be part of the most requested files. It's recommended to exclude the package only if you have total confidence it won't be called once Opcache Preloading is enabled.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003eselfExclude();\n```\n\n### Generation\n\n#### `memoryLimit()`\n\nBy default, Preloader defaults a memory limit of 32MB, which is enough for *most* applications. The Preloader will generate a list of files until that memory limit is reached.\n\nYou can set your own memory limit in **MB**.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003ememoryLimit(32);\n```\n\nThis takes into account the `memory_consumption` key of each script cached in Opcache, not the real file size.\n\n\u003e This limit doesn't have any relation with Opcache memory limit. \n\nTo disable the limit, use `memoryLimit(0)`. This will list **ALL** available files from Opcache.\n\n#### `useRequire()`\n\nBy default, the Preloader will upload the files to Opcache using `opcache_compile_file()`. This avoids executing any file in your project, but no links (traits, interfaces, extended classes, ...) will be resolved from the files compiled. You may have some warnings of unresolved links when preloading (nothing too dangerous).\n\nYou can change this using `useRequire()`, which changes to  `require_once`, along the path the Composer Autoloader (usually at `vendor/autoload.php`) to resolve the links.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003euseRequire(__DIR__ . '/../vendor/autoload.php');\n```\n\n\u003e You may get some warnings when compiling a file with unresolved links. These are not critical, since these files usually are the least requested in your application.\n\n#### `ignoreNotFound()`\n\nSome applications may create files at runtime that are genuinely cached by Opcache, but doesn't exist when the application is firstly deployed.\n\nTo avoid this problem, you can use the `ignoreNotFound()`, which will compile a script that ignore files not found or are unreadable.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003eignoreNotFound();\n```\n\n\u003e If the file is readable but its preloading returns an error, it will throw an exception nonetheless.\n\n### Compilation\n\n#### `writeTo()`\n\nThis will automatically create a PHP-ready script to preload your application. It will return `true` on success, and `false` when the when the conditions are not met.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003ewriteTo(__DIR__ . '/preloader.php');\n```\n\nYou can issue `false` as second parameter to not overwrite any existing file in the write path. If a file is found, no preload logic will be run. \n\n#### `getList()`\n\nYou can retrieve the raw list of files that should be included as an array using `getList()`.\n\n```php\n\u003c?php\n\nuse Ninja\\Preloader\\Preloader;\n\nPreloader::make()-\u003egetList();\n```\n\nThis may become handy if you have your own script, or you just want to tinker around it.\n\n## Safe Preloader\n\nThis package comes with a handy Safe Preloader, located in `helpers/safe_preloader.php`.\n\nWhat it does is very simple: it registers a shutdown function for PHP that is executed after the preload script finishes and registers any error the script may have returned so you can debug it.\n\nTo use it, copy the file into an accessible path for PHP, and along with the real preloader script, reference it in your `php.ini`:\n\n```ini\nopcache.preload=/www/app/safe_preloader.php\n```\n\n```php\n\u003c?php\n// /www/app/safe_preloader.php\n\nregister_shutdown_function(function (): void {\n    $error = error_get_last();\n    if (!$error) {\n        return;\n    }\n    echo 'Preloader Script has stopped with an error:' . \\PHP_EOL;\n    echo 'Message: ' . $error['message'] . \\PHP_EOL;\n    echo 'File: ' . $error['file'] . \\PHP_EOL;\n});\n\n// require_once /* Path to your preload script */\nrequire_once '/www/app/preloader.php';\n```\n\nTechnically speaking, the Opcache preloads the files in a different process, so there shouldn't be a problem using this safe-preloader. \n\n## Example\n\nOkay. Let's say we have a codebase with thousands of files. We don't know any metrics, so we will generate a preloader script if the request hits the lottery 1 on 100, with a memory limit of 64MB.\n\n```php\n\u003c?php\n// index.php\n\nuse Framework\\App;\nuse Ninja\\Preloader\\Preloader;\n\nrequire __DIR__ . '/../vendor/autoload.php';\n\n$app = App::make();\n\n$response = $app-\u003erun();\n\n$response-\u003esendToBrowser();\n\nPreloader::make()\n    -\u003ewhenOneIn(100)\n    -\u003ememoryLimit(64)\n    -\u003ewriteTo(PHP_LOCALSTATEDIR . '/preload.php'); // put it in /var.;\n```\n\n## Security\n\nIf you discover any security related issues, please email yosoy@diego.ninja instead of using the issue tracker.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiego-ninja%2Fpreloader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiego-ninja%2Fpreloader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiego-ninja%2Fpreloader/lists"}