Situación actual: PHP2Shell. Dos vulnerabilidades críticas de PHP (CVSS 9.2) permiten ejecutar código malicioso sin autenticación. Parches desde el 21/10/2026.Qué hacer ahora →

Namespaces y autoloading (PSR-4)

Los namespaces ordenan el código PHP y el autoloading carga las clases justo cuando se necesitan. Aquí verá cómo PSR-4 asocia nombres de clase con archivos y por qué hay que revisar el autoloader tras un incidente.

Actualizado 5 min de lecturaConocimiento de PHP

En resumen: en PHP, los namespaces son algo así como carpetas para los nombres de clase: App\Rechnung\Pdf y Bibliothek\Pdf pueden coexistir sin molestarse. El autoloading hace que PHP cargue una clase solo cuando se necesita por primera vez. El estándar PSR-4 establece cómo un nombre de clase se convierte en una ruta de archivo; Composer genera después el autoloader correspondiente. Como este autoloader se ejecuta en cada petición, es una de las primeras cosas que se revisan tras un incidente de seguridad.

Por qué PHP necesita namespaces

Los namespaces existen desde PHP 5.3.0. Antes, todas las clases y funciones compartían un único espacio de nombres global. Si dos bibliotecas se llamaban Logger, saltaba el error. Los desarrolladores se las arreglaban con nombres largos como Firma_Modul_Unterbereich_Logger.

El manual de PHP menciona dos problemas que resuelven los namespaces: las colisiones de nombres entre el código propio, las clases internas de PHP y las bibliotecas de terceros, y los nombres excesivamente largos surgidos solo para sortear esas colisiones. Para quienes toman decisiones significa que solo con los namespaces resultó viable combinar decenas de paquetes ajenos en un proyecto, como hoy es habitual con Composer.

Namespaces en la práctica: namespace, use, alias

Un archivo declara su namespace en la primera instrucción. Con use se traen clases de otros namespaces, si se desea con un nombre más corto.

<?php
declare(strict_types=1);

namespace App\Rechnung;

use App\Kunde\Kunde;
use Psr\Log\LoggerInterface as Log;

final class PdfErzeuger
{
    public function __construct(private Log $log) {}

    public function erzeugen(Kunde $kunde): string
    {
        $this->log->info('PDF erzeugt', ['kunde' => $kunde->id]);
        return \sprintf('Rechnung für %s', $kunde->name);
    }
}

El nombre completo de esta clase es App\Rechnung\PdfErzeuger. La barra invertida inicial en \sprintf remite expresamente a la función global de PHP.

Autoloading: cargar las clases cuando se necesitan

Sin autoloading, cada script tendría que incluir con require todos los archivos necesarios. Con spl_autoload_register() se registra en su lugar una función a la que PHP llama en cuanto se usa una clase, una interfaz, un trait o un enum desconocidos. Recibe el nombre de la clase y carga el archivo correspondiente.

<?php
spl_autoload_register(function (string $klasse): void {
    $praefix = 'App\\';
    $basis   = __DIR__ . '/src/';

    if (!str_starts_with($klasse, $praefix)) {
        return; // no es de su competencia, le toca al siguiente autoloader
    }
    $datei = $basis . str_replace('\\', '/', substr($klasse, strlen($praefix))) . '.php';
    if (is_file($datei)) {
        require $datei;
    }
});

spl_autoload_register() puede llamarse varias veces. PHP consulta entonces los autoloaders registrados uno tras otro hasta que alguno ha cargado la clase. En la práctica, las aplicaciones grandes suelen tener varios: el autoloader de Composer para las bibliotecas, uno propio del CMS y otros de plugins o módulos. Para los administradores significa que el código que se carga realmente en una petición resulta de la combinación de todos estos autoloaders y no solo de la estructura de carpetas.

El manual desaconseja encarecidamente lanzar excepciones en un autoloader; PSR-4 lo prohíbe expresamente. La antigua función __autoload() se marcó como obsoleta en PHP 7.2.0 y se eliminó en PHP 8.0.0.

PSR-4: del nombre de clase a la ruta del archivo

PSR-4 es un estándar de PHP-FIG. Un nombre de clase completo comienza con un namespace de fabricante. Un prefijo del namespace se asigna a un directorio base, el resto del nombre da las subcarpetas y el archivo termina en .php. Las mayúsculas y minúsculas deben coincidir exactamente. Así se ve la asignación en composer.json:

{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}
Nombre de clase Archivo
App\Kunde\Kunde src/Kunde/Kunde.php
App\Rechnung\PdfErzeuger src/Rechnung/PdfErzeuger.php
App\Rechnung\Pdf\Vorlage src/Rechnung/Pdf/Vorlage.php

Un tropiezo clásico son las mayúsculas y minúsculas. En equipos de desarrollo con Windows o macOS, el sistema de archivos a menudo no distingue entre Kunde.php y kunde.php; en un servidor Linux, sí. Una aplicación que funciona en local no encuentra entonces una clase en el servidor. La regla de PSR-4 de usar los nombres exactamente con la grafía correcta evita estas sorpresas en el despliegue.

Además de psr-4, Composer conoce classmap para código sin estructura estándar y files para archivos que se cargan en cada petición, por ejemplo funciones auxiliares. Otros estándares de PHP-FIG se describen en la página Estándares PSR.

Optimizar el autoloader en producción

En producción, lo mejor es que el autoloader ya no busque en el sistema de archivos, sino que consulte una lista ya preparada. Composer ofrece para ello dos niveles:

  1. composer install --no-dev --optimize-autoloader convierte las reglas PSR-4 en una lista de clases. Según la documentación de Composer, es lo recomendado para producción.
  2. --classmap-authoritative va más allá: las clases se cargan exclusivamente desde la lista. Los archivos no incluidos en ella, el autoloader ya no los carga en absoluto.
  3. En cada despliegue se regenera la lista, para que se encuentren las clases nuevas.

Autoloading y seguridad tras PHP2Shell

PHP2Shell afecta al intérprete de PHP, no al autoloader. Siguen siendo obligatorias la actualización a PHP 8.5.12, 8.4.27, 8.3.36 o 8.2.35 y el reinicio de todos los workers. Tras un posible incidente, sin embargo, el autoloader merece una atención especial: vendor/autoload.php y todos los archivos registrados en files se ejecutan en cada petición. Una línea introducida allí actúa, por tanto, en todo el sitio web sin que haya un archivo nuevo llamativo en la carpeta de cargas.

Compruebe, por eso, si vendor y los archivos de autoload coinciden con el estado revisado del control de versiones. Resultan útiles los artículos Encontrar archivos modificados recientemente y Comparar los archivos del núcleo del CMS con el original. En caso de duda, un vendor regenerado desde el archivo lock es más seguro que cualquier reparación puntual.

¿Cómo ayuda PHP SOS en concreto?

  • Comparamos vendor, el autoloader y los archivos de entrada con el estado revisado y marcamos cada desviación.
  • Restablecemos el conjunto de paquetes desde el archivo lock y configuramos un autoloader optimizado.
  • Comprobamos que solo la carpeta pública esté en el webroot y que el código fuente no sea accesible directamente por URL.
  • En caso de infección nos encargamos de la limpieza como parte de la eliminación de malware y documentamos el resultado.

Preguntas frecuentes

¿Desde cuándo hay namespaces en PHP?

Desde PHP 5.3.0. Según el manual, resuelven dos problemas: las colisiones de nombres entre el código propio, PHP y bibliotecas de terceros, y los nombres de clase excesivamente largos que solo surgían para evitar esas colisiones.

¿Qué diferencia hay entre PSR-0 y PSR-4?

Ambos asocian nombres de clase con rutas de archivo. En PSR-4, el prefijo del namespace no se repite en la ruta del archivo, lo que da directorios más planos. PHP-FIG clasifica PSR-0 como obsoleto; PSR-4 es el estándar recomendado.

¿Sigue funcionando __autoload()?

No. __autoload() se marcó como obsoleta en PHP 7.2.0 y se eliminó en PHP 8.0.0. Hoy los autoloaders se registran con spl_autoload_register(), en la práctica casi siempre mediante el autoloader que genera Composer.

¿Debo regenerar el autoloader tras crear una clase nueva?

Con reglas puramente PSR-4, no; según la documentación de Composer, esa es precisamente una ventaja de PSR-4. Quien usa en producción una lista optimizada de clases debe regenerarla en cada despliegue.

Fuentes

Contacto inmediato

Cada hora cuenta. Escríbanos ahora.

Describa brevemente el sistema, la versión de PHP y lo que ha observado. Nos pondremos en contacto, aclararemos la situación y trabajaremos en remoto hasta que el incidente quede cerrado y documentado.

Ayuda inmediata