• Stars
    star
    428
  • Rank 98,108 (Top 2 %)
  • Language
    PHP
  • License
    MIT License
  • Created over 4 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Preloader helper to create a PHP-ready preload script from Opcache.

 Braden Collum - Unsplash (UL) #9HI8UJMSdZA

Latest Version on Packagist License Coverage Status

Opcache Preloader

Get the best options to keep your application fast as ever, with just one line.

This package generates a PHP preloading script from your Opcache statistics automatically. No need to hack your way in.

If you're looking for preloading your Laravel project, check Laragear Preload.

Table of Contents

Requirements

Installation

Require this using Composer into your project

composer require darkghosthunter/preloader

This package doesn't require ext-opcache to install. Just be sure to have it enabled in your application server.

Usage

Anywhere in your application, where Opcache is enabled and running, call Preloader with where to output the compiled script:

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->writeTo(__DIR__.'/preloader.php');

This 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.

www
└── app
    β”œβ”€β”€ PreloaderCall.php
    └── preload.php

Once generated, tell PHP to use this file as a preloader at start up in your php.ini.

opcache.preload=/www/app/preload.php

Once 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.

If you use Preloader when Opcache is disabled or without hits, you will get an Exception.

How it works

This 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.

Since 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.

Don't worry, you can configure what and how compile the list.

Configuration

You can configure the Preloader to run when a condition is met, limit the file list, among what other things.

Conditions

when()

This method executes the given callable and checks if the preloader should compile the list or not based on what the callable returning value evaluates.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->when(fn () => $app->cache()->get('should_run'));

This is handy if you can combine the condition with your own application logic, like a given number of requests, or an external signal.

whenOneIn()

This is method is just a helper to allows you to quickly generate a Preloader script in one of a given number of random chances.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->whenOneIn(50);

For example, the above makes the Preloader generate a compiled list one in fifty chances.

Listing

append()

You 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.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->append([
    __DIR__ . '/files/*/more_files', 
    __DIR__ . '/classes/'
]);

If the files you're adding are already in the compiled list, these will be removed from the included files to avoid effective duplicates.

This packages includes Symfony Finder, so as an alternative you can pass a closure that receives the Finder instance along with the files you want to append.

<?php

use Symfony\Component\Finder\Finder;
use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->append(function (Finder $find) {
    $find->files()->in('/package')->name(['*.php', '*.twig']);
});

The exclude() method take precedence over append(). If you exclude a file that is later appended, you won't exclude it at all.

exclude()

This 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.

You can pass an array of paths, which is good if you already have a list ready to exclude.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->exclude([
    __DIR__ . '/files/*/more_files',
    __DIR__ . '/vendor'
]);

This packages includes Symfony Finder, so as an alternative you can pass a Closure receiving the Finder instance along with the files you want to exclude.

<?php

use Symfony\Component\Finder\Finder;
use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->exclude(function (Finder $find) {
    $find->files()->in('/package')->name(['*.php', '*.twig']);
});

The exclude() method take precedence over append(). If you exclude a file that is later appended, you won't exclude it at all.

selfExclude()

Automatically excludes the Package files from the Preload list.

By 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.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->selfExclude();

Generation

memoryLimit()

By 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.

You can set your own memory limit in MB.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->memoryLimit(32);

This takes into account the memory_consumption key of each script cached in Opcache, not the real file size.

This limit doesn't have any relation with Opcache memory limit.

To disable the limit, use memoryLimit(0). This will list ALL available files from Opcache.

useRequire()

By 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).

You 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.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->useRequire(__DIR__ . '/../vendor/autoload.php');

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.

ignoreNotFound()

Some applications may create files at runtime that are genuinely cached by Opcache, but doesn't exist when the application is firstly deployed.

To avoid this problem, you can use the ignoreNotFound(), which will compile a script that ignore files not found or are unreadable.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->ignoreNotFound();

If the file is readable but its preloading returns an error, it will throw an exception nonetheless.

Compilation

writeTo()

This 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.

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->writeTo(__DIR__ . '/preloader.php');

You 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.

getList()

You can retrieve the raw list of files that should be included as an array using getList().

<?php

use DarkGhostHunter\Preloader\Preloader;

Preloader::make()->getList();

This may become handy if you have your own script, or you just want to tinker around it.

Safe Preloader

This packages comes with a handy Safe Preloader, located in helpers/safe_preloader.php.

What 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.

To use it, copy the file into an accessible path for PHP, and along with the real preloader script, reference it in your 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';

Technically speaking, the Opcache preloads the files in a different process, so there shouldn't be a problem using this safe-preloader.

Example

Okay. Let's say we have a codebase with thousand 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.

<?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.;

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

The MIT License (MIT). Please see License File for more information.

More Repositories

1

Larapass

Authenticate users with just their device, fingerprint or biometric data. Goodbye passwords!
PHP
580
star
2

Laraguard

"On-premises 2FA Authentication for all your users out-of-the-box
PHP
267
star
3

Laraload

Effortlessly create a PHP preload script for your Laravel project.
PHP
210
star
4

Laraconfig

Per-user settings repository system for Laravel
PHP
173
star
5

Laratraits

A collection of useful traits for your Laravel application.
PHP
144
star
6

Captchavel

Integrate reCAPTCHA into your Laravel app better than the Big G itself!
PHP
96
star
7

RememberableQuery

Remember your Query results using only one method. Yes, only one.
PHP
49
star
8

Larahelp

Supercharge your Laravel projects with more than 25 useful global helpers.
PHP
49
star
9

Passless

Passwordless Authentication Driver for Laravel. Just add water.
PHP
45
star
10

Laralerts

Quickly create one or multiple Alerts from your backend.
PHP
45
star
11

Laralocker

Avoid race conditions in your Jobs, Listeners and Notifications with this simple locker reservation system.
PHP
44
star
12

Larapoke

Keep your forms alive, avoid TokenMismatchException by gently poking your Laravel app.
PHP
43
star
13

Larasane

Quickly and easily secure HTML text.
PHP
39
star
14

Tailstart

HTML Components ready to style with Tailwind CSS
HTML
8
star
15

FlowSdk

Flow SDK for PHP to process payments, made unofficially.
PHP
5
star
16

Laraflow

Flow SDK for Laravel
PHP
4
star
17

RutUtils

A complete library for creating, manipulating and generating chilean RUTs or RUNs.
PHP
3
star
18

Laradate

Parse a date from the URL, receive it as a `Carbon` instance in your controller.
PHP
2
star
19

Fluid

A flexible class based on the famous Laravel's Fluent and Eloquent Model class.
PHP
2
star
20

Larabanker

This package connects the non-official Transbank SDK into your Laravel Application.
PHP
2
star
21

TransbankApi

Transbank SDK no oficial para PHP 8.0
PHP
2
star
22

Transbanker

Transbank connector for Laravel
PHP
1
star
23

Lararut

RutUtils integration for Laravel.
PHP
1
star