Navigation

Php

PHP preload_script Optimization: Boosting Application Start Time

Master PHP's preload_script feature to dramatically improve application startup performance. Learn advanced techniques for optimizing class loading, memory usage, and implementing intelligent preloading strategies for production environments.

Summary: Master PHP's preload_script feature to dramatically improve application startup performance. Learn advanced techniques for optimizing class loading, memory usage, and implementing intelligent preloading strategies for production environments.

Table Of Contents

Introduction

PHP's preload_script functionality, introduced in PHP 7.4, represents one of the most significant performance improvements available to modern PHP applications. By preloading frequently used classes and functions into memory during server startup, you can eliminate the overhead of file parsing and compilation on every request, resulting in substantial performance gains.

Understanding and implementing effective preloading strategies can reduce application bootstrap time by 30-50% or more, especially in complex applications with large dependency graphs. This optimization is particularly valuable for high-traffic applications where every millisecond of response time matters, making preloading an essential tool in the performance optimization toolkit.

Understanding PHP Preloading

How Preloading Works

PHP preloading loads and compiles specified PHP files into memory when the server starts, making them immediately available for all subsequent requests:

// Basic preload example
// preload.php
<?php

// Preload core application files
require_once __DIR__ . '/src/Core/Application.php';
require_once __DIR__ . '/src/Core/Container.php';
require_once __DIR__ . '/src/Core/Router.php';

// Preload commonly used classes
$commonClasses = [
    'App\\Models\\User',
    'App\\Models\\Product',
    'App\\Services\\AuthService',
    'App\\Services\\PaymentService'
];

foreach ($commonClasses as $class) {
    if (class_exists($class)) {
        // Force class loading
        class_parents($class);
        class_implements($class);
    }
}

echo "Preloaded " . count(get_declared_classes()) . " classes\n";

Benefits and Limitations

Benefits:

  • Eliminates file I/O overhead for preloaded files
  • Reduces CPU usage from repeated parsing/compilation
  • Improves memory efficiency through shared compilation
  • Enables better OPcache optimization

Limitations:

  • Requires server restart for changes
  • Increases memory usage during server startup
  • Not suitable for development environments
  • Dependencies must be carefully managed

Advanced Preloading Strategies

Intelligent Class Discovery

Create a system to automatically discover and preload classes:

// src/Preload/ClassDiscovery.php
<?php

namespace App\Preload;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use ReflectionClass;

class ClassDiscovery
{
    private array $loadedClasses = [];
    private array $excludePatterns = [];
    private array $includePaths = [];
    private int $maxMemoryUsage;

    public function __construct(int $maxMemoryUsageMB = 256)
    {
        $this->maxMemoryUsage = $maxMemoryUsageMB * 1024 * 1024;
    }

    public function addIncludePath(string $path): self
    {
        $this->includePaths[] = realpath($path);
        return $this;
    }

    public function addExcludePattern(string $pattern): self
    {
        $this->excludePatterns[] = $pattern;
        return $this;
    }

    public function discoverClasses(): array
    {
        $classes = [];
        
        foreach ($this->includePaths as $path) {
            $classes = array_merge($classes, $this->scanDirectory($path));
        }

        return $this->prioritizeClasses($classes);
    }

    public function preloadClasses(array $classes): array
    {
        $stats = [
            'attempted' => 0,
            'loaded' => 0,
            'skipped' => 0,
            'errors' => 0,
            'memory_used' => 0
        ];

        $initialMemory = memory_get_usage();

        foreach ($classes as $classInfo) {
            $stats['attempted']++;

            if (memory_get_usage() > $this->maxMemoryUsage) {
                $stats['skipped']++;
                continue;
            }

            try {
                if ($this->preloadClass($classInfo)) {
                    $stats['loaded']++;
                    $this->loadedClasses[] = $classInfo['class'];
                } else {
                    $stats['skipped']++;
                }
            } catch (\Throwable $e) {
                $stats['errors']++;
                error_log("Preload error for {$classInfo['class']}: " . $e->getMessage());
            }
        }

        $stats['memory_used'] = memory_get_usage() - $initialMemory;
        return $stats;
    }

    private function scanDirectory(string $path): array
    {
        $classes = [];
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS)
        );

        foreach ($iterator as $file) {
            if ($file->getExtension() !== 'php') {
                continue;
            }

            if ($this->shouldExcludeFile($file->getPathname())) {
                continue;
            }

            $classInfo = $this->extractClassInfo($file->getPathname());
            if ($classInfo) {
                $classes[] = $classInfo;
            }
        }

        return $classes;
    }

    private function extractClassInfo(string $filepath): ?array
    {
        $content = file_get_contents($filepath);
        
        // Extract namespace
        if (preg_match('/namespace\s+([^;]+);/', $content, $matches)) {
            $namespace = trim($matches[1]);
        } else {
            $namespace = '';
        }

        // Extract class/interface/trait name
        if (preg_match('/(?:class|interface|trait)\s+(\w+)/', $content, $matches)) {
            $className = $matches[1];
            $fullClassName = $namespace ? $namespace . '\\' . $className : $className;

            return [
                'class' => $fullClassName,
                'file' => $filepath,
                'namespace' => $namespace,
                'size' => filesize($filepath),
                'modified' => filemtime($filepath),
                'priority' => $this->calculatePriority($fullClassName, $content)
            ];
        }

        return null;
    }

    private function calculatePriority(string $className, string $content): int
    {
        $priority = 0;

        // Higher priority for commonly used patterns
        $patterns = [
            '/class.*extends.*Controller/' => 10,
            '/class.*implements.*ServiceInterface/' => 8,
            '/trait/' => 5,
            '/interface/' => 7,
            '/abstract class/' => 6,
            '/__construct/' => 3,
            '/use.*Injectable/' => 4
        ];

        foreach ($patterns as $pattern => $points) {
            if (preg_match($pattern, $content)) {
                $priority += $points;
            }
        }

        // Adjust priority based on class name patterns
        if (str_contains($className, 'Controller')) $priority += 15;
        if (str_contains($className, 'Service')) $priority += 12;
        if (str_contains($className, 'Repository')) $priority += 10;
        if (str_contains($className, 'Model')) $priority += 8;

        return $priority;
    }

    private function prioritizeClasses(array $classes): array
    {
        // Sort by priority (highest first)
        usort($classes, fn($a, $b) => $b['priority'] <=> $a['priority']);
        return $classes;
    }

    private function shouldExcludeFile(string $filepath): bool
    {
        foreach ($this->excludePatterns as $pattern) {
            if (fnmatch($pattern, $filepath)) {
                return true;
            }
        }
        return false;
    }

    private function preloadClass(array $classInfo): bool
    {
        if (class_exists($classInfo['class'], false) || 
            interface_exists($classInfo['class'], false) || 
            trait_exists($classInfo['class'], false)) {
            return false; // Already loaded
        }

        require_once $classInfo['file'];

        // Verify the class was loaded
        return class_exists($classInfo['class'], false) || 
               interface_exists($classInfo['class'], false) || 
               trait_exists($classInfo['class'], false);
    }

    public function getLoadedClasses(): array
    {
        return $this->loadedClasses;
    }
}

Dependency-Aware Preloading

Implement smart dependency resolution for preloading:

// src/Preload/DependencyResolver.php
<?php

namespace App\Preload;

use ReflectionClass;
use ReflectionException;

class DependencyResolver
{
    private array $dependencyGraph = [];
    private array $resolved = [];
    private array $resolving = [];

    public function buildDependencyGraph(array $classes): array
    {
        foreach ($classes as $class) {
            $this->analyzeDependencies($class);
        }

        return $this->dependencyGraph;
    }

    public function getLoadOrder(array $classes): array
    {
        $this->buildDependencyGraph($classes);
        $loadOrder = [];

        foreach ($classes as $class) {
            $this->resolveDependencies($class, $loadOrder);
        }

        return array_unique($loadOrder);
    }

    private function analyzeDependencies(string $className): void
    {
        if (isset($this->dependencyGraph[$className])) {
            return;
        }

        try {
            $reflection = new ReflectionClass($className);
            $dependencies = [];

            // Analyze parent class
            $parent = $reflection->getParentClass();
            if ($parent) {
                $dependencies[] = $parent->getName();
            }

            // Analyze interfaces
            foreach ($reflection->getInterfaces() as $interface) {
                $dependencies[] = $interface->getName();
            }

            // Analyze traits
            foreach ($reflection->getTraits() as $trait) {
                $dependencies[] = $trait->getName();
            }

            // Analyze constructor dependencies
            $constructor = $reflection->getConstructor();
            if ($constructor) {
                foreach ($constructor->getParameters() as $parameter) {
                    $type = $parameter->getType();
                    if ($type && !$type->isBuiltin()) {
                        $dependencies[] = $type->getName();
                    }
                }
            }

            // Analyze property type hints
            foreach ($reflection->getProperties() as $property) {
                $type = $property->getType();
                if ($type && !$type->isBuiltin()) {
                    $dependencies[] = $type->getName();
                }
            }

            $this->dependencyGraph[$className] = array_unique($dependencies);

        } catch (ReflectionException $e) {
            $this->dependencyGraph[$className] = [];
        }
    }

    private function resolveDependencies(string $className, array &$loadOrder): void
    {
        if (isset($this->resolved[$className])) {
            return;
        }

        if (isset($this->resolving[$className])) {
            // Circular dependency detected - log and continue
            error_log("Circular dependency detected: {$className}");
            return;
        }

        $this->resolving[$className] = true;

        // Resolve dependencies first
        $dependencies = $this->dependencyGraph[$className] ?? [];
        foreach ($dependencies as $dependency) {
            if (isset($this->dependencyGraph[$dependency])) {
                $this->resolveDependencies($dependency, $loadOrder);
            }
        }

        $loadOrder[] = $className;
        $this->resolved[$className] = true;
        unset($this->resolving[$className]);
    }

    public function validateDependencies(array $classes): array
    {
        $issues = [];

        foreach ($classes as $class) {
            $dependencies = $this->dependencyGraph[$class] ?? [];
            
            foreach ($dependencies as $dependency) {
                if (!in_array($dependency, $classes) && 
                    !class_exists($dependency, false) && 
                    !interface_exists($dependency, false) && 
                    !trait_exists($dependency, false)) {
                    
                    $issues[] = [
                        'class' => $class,
                        'missing_dependency' => $dependency,
                        'type' => 'missing'
                    ];
                }
            }
        }

        return $issues;
    }
}

Configuration-Driven Preloading

Create a flexible configuration system:

// src/Preload/PreloadConfig.php
<?php

namespace App\Preload;

class PreloadConfig
{
    private array $config;

    public function __construct(string $configPath)
    {
        $this->config = $this->loadConfig($configPath);
    }

    public function getIncludePaths(): array
    {
        return $this->config['include_paths'] ?? [];
    }

    public function getExcludePatterns(): array
    {
        return $this->config['exclude_patterns'] ?? [];
    }

    public function getMaxMemoryUsage(): int
    {
        return $this->config['max_memory_mb'] ?? 256;
    }

    public function getPreloadStrategies(): array
    {
        return $this->config['strategies'] ?? ['auto'];
    }

    public function getClassPriorities(): array
    {
        return $this->config['class_priorities'] ?? [];
    }

    public function isEnabled(): bool
    {
        return $this->config['enabled'] ?? true;
    }

    public function shouldPreloadVendor(): bool
    {
        return $this->config['preload_vendor'] ?? false;
    }

    public function getVendorWhitelist(): array
    {
        return $this->config['vendor_whitelist'] ?? [];
    }

    private function loadConfig(string $configPath): array
    {
        if (!file_exists($configPath)) {
            return $this->getDefaultConfig();
        }

        $config = json_decode(file_get_contents($configPath), true);
        
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new \RuntimeException('Invalid preload configuration JSON: ' . json_last_error_msg());
        }

        return array_merge($this->getDefaultConfig(), $config);
    }

    private function getDefaultConfig(): array
    {
        return [
            'enabled' => true,
            'max_memory_mb' => 256,
            'include_paths' => [
                'src/',
                'app/'
            ],
            'exclude_patterns' => [
                '*/tests/*',
                '*/Test/*',
                '*/migrations/*',
                '*/cache/*',
                '*/storage/*'
            ],
            'strategies' => ['auto', 'dependency', 'priority'],
            'preload_vendor' => false,
            'vendor_whitelist' => [
                'illuminate/support',
                'illuminate/container',
                'illuminate/http'
            ],
            'class_priorities' => [
                '*Controller' => 20,
                '*Service' => 15,
                '*Repository' => 12,
                '*Model' => 10,
                '*Interface' => 8,
                '*Trait' => 5
            ]
        ];
    }
}

Production-Ready Preload System

Complete Preload Manager

// src/Preload/PreloadManager.php
<?php

namespace App\Preload;

class PreloadManager
{
    private PreloadConfig $config;
    private ClassDiscovery $discovery;
    private DependencyResolver $resolver;
    private array $stats = [];

    public function __construct(
        PreloadConfig $config,
        ClassDiscovery $discovery,
        DependencyResolver $resolver
    ) {
        $this->config = $config;
        $this->discovery = $discovery;
        $this->resolver = $resolver;
    }

    public function execute(): array
    {
        if (!$this->config->isEnabled()) {
            return ['status' => 'disabled'];
        }

        $startTime = microtime(true);
        $initialMemory = memory_get_usage();

        try {
            // Configure discovery
            $this->configureDiscovery();

            // Discover classes
            $classes = $this->discovery->discoverClasses();
            $this->stats['discovered_classes'] = count($classes);

            // Apply strategies
            $classesToPreload = $this->applyStrategies($classes);
            $this->stats['selected_classes'] = count($classesToPreload);

            // Preload classes
            $preloadStats = $this->preloadClasses($classesToPreload);
            $this->stats = array_merge($this->stats, $preloadStats);

            // Generate report
            $this->stats['execution_time'] = microtime(true) - $startTime;
            $this->stats['memory_used'] = memory_get_usage() - $initialMemory;
            $this->stats['status'] = 'success';

            $this->writeStatsFile();
            return $this->stats;

        } catch (\Throwable $e) {
            $this->stats['status'] = 'error';
            $this->stats['error'] = $e->getMessage();
            $this->stats['execution_time'] = microtime(true) - $startTime;

            error_log("Preload error: " . $e->getMessage());
            return $this->stats;
        }
    }

    private function configureDiscovery(): void
    {
        $this->discovery->setMaxMemoryUsage($this->config->getMaxMemoryUsage());

        foreach ($this->config->getIncludePaths() as $path) {
            $this->discovery->addIncludePath($path);
        }

        foreach ($this->config->getExcludePatterns() as $pattern) {
            $this->discovery->addExcludePattern($pattern);
        }
    }

    private function applyStrategies(array $classes): array
    {
        $strategies = $this->config->getPreloadStrategies();
        $selected = $classes;

        foreach ($strategies as $strategy) {
            $selected = match ($strategy) {
                'dependency' => $this->applyDependencyStrategy($selected),
                'priority' => $this->applyPriorityStrategy($selected),
                'memory' => $this->applyMemoryStrategy($selected),
                'vendor' => $this->applyVendorStrategy($selected),
                default => $selected
            };
        }

        return $selected;
    }

    private function applyDependencyStrategy(array $classes): array
    {
        $classNames = array_column($classes, 'class');
        $loadOrder = $this->resolver->getLoadOrder($classNames);
        
        // Reorder classes according to dependency resolution
        $ordered = [];
        foreach ($loadOrder as $className) {
            foreach ($classes as $classInfo) {
                if ($classInfo['class'] === $className) {
                    $ordered[] = $classInfo;
                    break;
                }
            }
        }

        return $ordered;
    }

    private function applyPriorityStrategy(array $classes): array
    {
        $priorities = $this->config->getClassPriorities();

        foreach ($classes as &$classInfo) {
            foreach ($priorities as $pattern => $priority) {
                if (fnmatch($pattern, $classInfo['class'])) {
                    $classInfo['priority'] += $priority;
                    break;
                }
            }
        }

        // Sort by priority
        usort($classes, fn($a, $b) => $b['priority'] <=> $a['priority']);
        return $classes;
    }

    private function applyMemoryStrategy(array $classes): array
    {
        $maxMemory = $this->config->getMaxMemoryUsage() * 1024 * 1024;
        $estimatedMemory = 0;
        $selected = [];

        foreach ($classes as $classInfo) {
            $estimatedSize = $classInfo['size'] * 2; // Rough estimate
            
            if ($estimatedMemory + $estimatedSize > $maxMemory) {
                break;
            }

            $selected[] = $classInfo;
            $estimatedMemory += $estimatedSize;
        }

        return $selected;
    }

    private function applyVendorStrategy(array $classes): array
    {
        if (!$this->config->shouldPreloadVendor()) {
            return array_filter($classes, fn($c) => !str_contains($c['file'], '/vendor/'));
        }

        $whitelist = $this->config->getVendorWhitelist();
        if (empty($whitelist)) {
            return $classes;
        }

        return array_filter($classes, function ($classInfo) use ($whitelist) {
            if (!str_contains($classInfo['file'], '/vendor/')) {
                return true; // Keep non-vendor classes
            }

            foreach ($whitelist as $allowed) {
                if (str_contains($classInfo['file'], "/vendor/{$allowed}/")) {
                    return true;
                }
            }

            return false;
        });
    }

    private function preloadClasses(array $classes): array
    {
        return $this->discovery->preloadClasses($classes);
    }

    private function writeStatsFile(): void
    {
        $statsFile = sys_get_temp_dir() . '/preload_stats.json';
        file_put_contents($statsFile, json_encode($this->stats, JSON_PRETTY_PRINT));
    }

    public function getStats(): array
    {
        return $this->stats;
    }
}

Optimized Production Preload Script

// preload_production.php
<?php

// Production preload script
declare(strict_types=1);

$startTime = microtime(true);

// Error handling
set_error_handler(function ($severity, $message, $file, $line) {
    if (error_reporting() & $severity) {
        throw new ErrorException($message, 0, $severity, $file, $line);
    }
});

try {
    // Configuration
    $configPath = __DIR__ . '/config/preload.json';
    $config = new App\Preload\PreloadConfig($configPath);

    // Initialize components
    $discovery = new App\Preload\ClassDiscovery($config->getMaxMemoryUsage());
    $resolver = new App\Preload\DependencyResolver();
    $manager = new App\Preload\PreloadManager($config, $discovery, $resolver);

    // Execute preloading
    $stats = $manager->execute();

    // Log results
    $executionTime = microtime(true) - $startTime;
    $memoryUsed = memory_get_usage();
    $peakMemory = memory_get_peak_usage();

    $logMessage = sprintf(
        "Preload completed: %d classes loaded in %.2fs, Memory: %.2fMB (Peak: %.2fMB)",
        $stats['loaded'] ?? 0,
        $executionTime,
        $memoryUsed / 1024 / 1024,
        $peakMemory / 1024 / 1024
    );

    error_log($logMessage);

    // Output for monitoring
    if (php_sapi_name() === 'cli') {
        echo $logMessage . "\n";
        echo "Stats: " . json_encode($stats, JSON_PRETTY_PRINT) . "\n";
    }

} catch (\Throwable $e) {
    $errorMessage = "Preload failed: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine();
    error_log($errorMessage);
    
    if (php_sapi_name() === 'cli') {
        echo $errorMessage . "\n";
    }
}

// Cleanup
restore_error_handler();

Framework-Specific Optimizations

Laravel Preloading

// laravel_preload.php
<?php

// Laravel-optimized preload script
require_once __DIR__ . '/vendor/autoload.php';

$laravel = require_once __DIR__ . '/bootstrap/app.php';
$kernel = $laravel->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->bootstrap();

// Preload Laravel core classes
$laravelCore = [
    // Application core
    Illuminate\Foundation\Application::class,
    Illuminate\Container\Container::class,
    
    // HTTP layer
    Illuminate\Http\Request::class,
    Illuminate\Http\Response::class,
    Illuminate\Routing\Router::class,
    
    // Database
    Illuminate\Database\Eloquent\Model::class,
    Illuminate\Database\Eloquent\Builder::class,
    Illuminate\Database\Query\Builder::class,
    
    // Collections
    Illuminate\Support\Collection::class,
    Illuminate\Database\Eloquent\Collection::class,
    
    // Commonly used facades
    Illuminate\Support\Facades\DB::class,
    Illuminate\Support\Facades\Cache::class,
    Illuminate\Support\Facades\Log::class,
];

// Preload application models
$models = glob(__DIR__ . '/app/Models/*.php');
foreach ($models as $model) {
    $className = 'App\\Models\\' . basename($model, '.php');
    if (class_exists($className)) {
        // Force loading of model relationships and scopes
        try {
            $instance = new $className;
            // Trigger relationship loading
            foreach (get_class_methods($instance) as $method) {
                if (str_starts_with($method, 'get') && str_ends_with($method, 'Attribute')) {
                    // Skip accessor methods during preload
                    continue;
                }
            }
        } catch (\Throwable $e) {
            // Skip models that can't be instantiated
        }
    }
}

// Preload service providers
$providers = config('app.providers', []);
foreach ($providers as $provider) {
    if (class_exists($provider)) {
        class_parents($provider);
        class_implements($provider);
    }
}

// Preload middleware
$middlewareGroups = config('middleware.groups', []);
foreach ($middlewareGroups as $group => $middlewares) {
    foreach ($middlewares as $middleware) {
        if (is_string($middleware) && class_exists($middleware)) {
            class_parents($middleware);
        }
    }
}

Symfony Preloading

// symfony_preload.php
<?php

// Symfony-optimized preload script
require_once __DIR__ . '/vendor/autoload.php';

use Symfony\Component\Finder\Finder;

// Preload Symfony core components
$symfonyCore = [
    Symfony\Component\HttpFoundation\Request::class,
    Symfony\Component\HttpFoundation\Response::class,
    Symfony\Component\HttpKernel\HttpKernel::class,
    Symfony\Component\DependencyInjection\Container::class,
    Symfony\Component\Routing\Router::class,
    Symfony\Component\EventDispatcher\EventDispatcher::class,
];

foreach ($symfonyCore as $class) {
    if (class_exists($class)) {
        class_parents($class);
        class_implements($class);
    }
}

// Preload application controllers
$finder = new Finder();
$finder->files()->in(__DIR__ . '/src/Controller')->name('*.php');

foreach ($finder as $file) {
    require_once $file->getRealPath();
}

// Preload services
$finder = new Finder();
$finder->files()->in(__DIR__ . '/src/Service')->name('*.php');

foreach ($finder as $file) {
    require_once $file->getRealPath();
}

Monitoring and Optimization

Preload Performance Monitor

// src/Preload/PerformanceMonitor.php
<?php

namespace App\Preload;

class PerformanceMonitor
{
    private array $metrics = [];
    private string $logFile;

    public function __construct(string $logFile = null)
    {
        $this->logFile = $logFile ?? sys_get_temp_dir() . '/preload_performance.log';
    }

    public function startMeasurement(string $name): void
    {
        $this->metrics[$name] = [
            'start_time' => microtime(true),
            'start_memory' => memory_get_usage(),
            'start_peak_memory' => memory_get_peak_usage()
        ];
    }

    public function endMeasurement(string $name): array
    {
        if (!isset($this->metrics[$name])) {
            throw new \InvalidArgumentException("Measurement '{$name}' not started");
        }

        $start = $this->metrics[$name];
        $result = [
            'name' => $name,
            'duration' => microtime(true) - $start['start_time'],
            'memory_used' => memory_get_usage() - $start['start_memory'],
            'peak_memory_increase' => memory_get_peak_usage() - $start['start_peak_memory'],
            'timestamp' => date('Y-m-d H:i:s')
        ];

        $this->logMeasurement($result);
        unset($this->metrics[$name]);

        return $result;
    }

    public function measureClass(string $className, callable $loader): array
    {
        $this->startMeasurement($className);
        
        try {
            $result = $loader();
            $measurement = $this->endMeasurement($className);
            $measurement['success'] = true;
            $measurement['result'] = $result;
            return $measurement;
        } catch (\Throwable $e) {
            $measurement = $this->endMeasurement($className);
            $measurement['success'] = false;
            $measurement['error'] = $e->getMessage();
            return $measurement;
        }
    }

    public function getSystemMetrics(): array
    {
        return [
            'php_version' => PHP_VERSION,
            'opcache_enabled' => function_exists('opcache_get_status') && opcache_get_status() !== false,
            'opcache_stats' => function_exists('opcache_get_status') ? opcache_get_status() : null,
            'memory_limit' => ini_get('memory_limit'),
            'current_memory' => memory_get_usage(),
            'peak_memory' => memory_get_peak_usage(),
            'declared_classes' => count(get_declared_classes()),
            'declared_interfaces' => count(get_declared_interfaces()),
            'declared_traits' => count(get_declared_traits()),
            'included_files' => count(get_included_files())
        ];
    }

    private function logMeasurement(array $measurement): void
    {
        $logEntry = json_encode($measurement) . "\n";
        file_put_contents($this->logFile, $logEntry, FILE_APPEND | LOCK_EX);
    }

    public function generateReport(): array
    {
        if (!file_exists($this->logFile)) {
            return ['error' => 'No performance data available'];
        }

        $lines = file($this->logFile, FILE_IGNORE_NEW_LINES);
        $measurements = array_map('json_decode', $lines);
        $measurements = array_filter($measurements, fn($m) => $m !== null);

        if (empty($measurements)) {
            return ['error' => 'No valid performance data'];
        }

        $totalDuration = array_sum(array_column($measurements, 'duration'));
        $totalMemory = array_sum(array_column($measurements, 'memory_used'));
        $successRate = count(array_filter($measurements, fn($m) => $m->success ?? false)) / count($measurements) * 100;

        return [
            'total_measurements' => count($measurements),
            'total_duration' => $totalDuration,
            'average_duration' => $totalDuration / count($measurements),
            'total_memory_used' => $totalMemory,
            'average_memory_per_class' => $totalMemory / count($measurements),
            'success_rate' => $successRate,
            'slowest_classes' => $this->getSlowestClasses($measurements, 10),
            'memory_heaviest' => $this->getMemoryHeaviestClasses($measurements, 10),
            'system_metrics' => $this->getSystemMetrics()
        ];
    }

    private function getSlowestClasses(array $measurements, int $limit): array
    {
        usort($measurements, fn($a, $b) => $b->duration <=> $a->duration);
        return array_slice($measurements, 0, $limit);
    }

    private function getMemoryHeaviestClasses(array $measurements, int $limit): array
    {
        usort($measurements, fn($a, $b) => $b->memory_used <=> $a->memory_used);
        return array_slice($measurements, 0, $limit);
    }
}

Related Posts

For more insights into PHP performance optimization and advanced server configurations, explore these related articles:

Conclusion

PHP preload_script optimization represents a powerful tool for dramatically improving application startup performance. By implementing intelligent preloading strategies, dependency resolution, and performance monitoring, you can achieve substantial performance gains while maintaining code quality and maintainability.

Key principles for effective preloading:

  • Strategic Selection: Preload only frequently used classes to maximize benefit
  • Dependency Management: Ensure proper loading order to avoid errors
  • Memory Awareness: Monitor memory usage to prevent server overload
  • Production Focus: Use preloading only in production environments
  • Continuous Monitoring: Track performance metrics to optimize strategies
  • Framework Integration: Leverage framework-specific optimizations

Preloading works best when combined with other optimization techniques like OPcache, proper caching strategies, and application-level optimizations. The performance gains are most significant in applications with large codebases, complex dependency graphs, and high request volumes.

Remember that preloading requires careful configuration and monitoring. Start with conservative settings, measure the impact, and gradually optimize based on your specific application characteristics and performance requirements.

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Php