Etiqueta: precarga

  • Autoload adaptativo en PHP: reducir tiempo de descubrimiento de archivos

    Autoload adaptativo en PHP: reducir tiempo de descubrimiento de archivos

    Este artículo explica cómo reducir el tiempo de descubrimiento de archivos en aplicaciones PHP mediante un autoload adaptativo que convierte mapas estáticos en una caché predictiva.

    Incluye patrón mínimo, integración con Composer y ejemplos prácticos para precargar y persistir la caché.

    Introducción

    Un autoloader estándar (por ejemplo PSR-4 con Composer) mapea namespaces a directorios y busca secuencialmente hasta encontrar un archivo. En proyectos grandes esa búsqueda repetida agrega latencia acumulada.

    El autoload adaptativo crea y mantiene una caché de rutas resueltas (en memoria o en disco) que se actualiza cuando cambia el árbol de clases, transformando búsquedas costosas en accesos determinísticos y rápidos.

    Prerrequisitos

    • Proyecto PHP que use autoload (Composer o autoloader propio).
    • Permiso para escribir un archivo de caché en disco (si se persiste entre peticiones).
    • Posibilidad de ejecutar scripts de Composer (si se integra con ganchos post-autoload-dump).
    • Opcional: soporte para opcache.preload para precargar rutas en entornos que lo permiten.

    Desarrollo

    Procedimiento

    La idea central es mantener un mapa (hash) de clase => ruta. En runtime se consulta primero esa caché; si la entrada existe se incluye la ruta inmediatamente. Si no, el autoloader realiza la búsqueda clásica, almacena el resultado en la caché y continúa.

    <?php
    spl_autoload_register(function ($class) {
        static $cache = [];
    
        if (isset($cache[$class])) {
            require $cache[$class];
            return;
        }
    
        $file = __DIR__ . '/' . str_replace('\\', '/', $class) . '.php';
        if (file_exists($file)) {
            $cache[$class] = $file;
            require $file;
        }
    });
    Lenguaje del código: PHP (php)

    Ese ejemplo mantiene la caché en memoria. Para persistir entre procesos, vuelca el array a JSON en disco después de cambios relevantes y vuelves a cargarlo al arrancar.

    Usar opcache.preload junto con una caché prellenada reduce aún más I/O en solicitudes recurrentes: el mapa pre-cargado evita lecturas repetidas desde disco.

    Integración con Composer

    Puedes enganchar un script a post-autoload-dump para reconstruir la caché adaptativa cuando Composer actualice el autoload. Ejemplo de snippet en composer.json:

    {
      "scripts": {
        "post-autoload-dump": [
          "php scripts/build-classmap-cache.php"
        ]
      }
    }
    Lenguaje del código: JSON / JSON con comentarios (json)

    En el script de construcción puedes combinar composer/autoload_classmap.php con tu caché adaptativa para obtener una base precisa y añadir hits observados en producción.

    <?php
    // scripts/build-classmap-cache.php
    $classmap = [];
    $composerMap = __DIR__ . '/../vendor/composer/autoload_classmap.php';
    if (file_exists($composerMap)) {
        $classmap = include $composerMap; // devuelve array clase => ruta
    }
    // Aquí podrías mergear con una caché existente o con datos de telemetría
    file_put_contents(__DIR__ . '/../storage/classmap-cache.json', json_encode($classmap, JSON_PRETTY_PRINT));
    Lenguaje del código: PHP (php)

    El ejemplo escribe un archivo JSON que el autoloader puede cargar al inicio para evitar búsquedas en disco en la primera petición.

    Ejemplos

    Lectura de la caché pre-generada en el arranque de la aplicación antes de registrar el autoloader dinámico:

    <?php
    $cacheFile = __DIR__ . '/storage/classmap-cache.json';
    $cache = [];
    if (file_exists($cacheFile)) {
        $cache = json_decode(file_get_contents($cacheFile), true);
    }
    
    spl_autoload_register(function ($class) use (&$cache) {
        if (isset($cache[$class])) {
            require $cache[$class];
            return;
        }
    
        // Fallback: búsqueda clásica y almacenamiento en caché
        $file = __DIR__ . '/' . str_replace('\\', '/', $class) . '.php';
        if (file_exists($file)) {
            $cache[$class] = $file;
            require $file;
            // Opcional: persistir incrementalmente o marcar para persistencia en shutdown
        }
    });
    Lenguaje del código: PHP (php)

    Este flujo permite que la primera petición use la caché en disco y las siguientes usen la versión en memoria, con posibilidad de actualizar el archivo cuando cambien las rutas.

    Checklist

    1. Generar una base de classmap (composer/autoload_classmap.php) o similar.
    2. Implementar caché en memoria y opcional persistencia en disco (JSON).
    3. Registrar autoloader que consulte la caché antes de buscar en disco.
    4. Integrar con Composer: script post-autoload-dump para reconstruir la caché cuando cambien dependencias.
    5. Considerar opcache.preload y precargar la caché en entornos que lo permitan.
    6. Medir y validar: comparar tiempo de arranque y perfil de I/O antes y después.

    Conclusión

    Un autoload adaptativo reduce búsquedas innecesarias convirtiendo mapas estáticos en una caché viva que aprende patrones de carga. El resultado: menos I/O, resolución de clases casi instantánea y mayor predictibilidad en perfiles de rendimiento.

    Implementa la caché en memoria con persistencia opcional, engancha la reconstrucción a Composer y considera opcache.preload para optimizar el comportamiento en producción.