PSR standards en PHP moderno

Avanzado
PHP
PHP
Actualizado: 19/04/2026

El ecosistema PHP ha madurado en gran medida gracias al PHP Framework Interoperability Group, conocido como PHP-FIG. Este colectivo publica PSR (PHP Standards Recommendations), un conjunto de estandares que permiten que bibliotecas de distintos autores y frameworks diferentes se entiendan sin fricciones.

Adoptar los PSR en tu codigo te alinea con el resto del ecosistema: tus clases se cargaran con cualquier autoloader compatible, tu codigo se revisara por cualquier formateador estandar y tus logs podran enviarse a cualquier biblioteca sin acoplamiento.

PSR-4: autoloading estandarizado

PSR-4 define como se cargan automaticamente las clases segun su nombre completo (namespace mas clase). La idea es simple: el nombre completo de una clase se traduce directamente a una ruta en disco, siguiendo una convencion explicita.

La regla base es que un prefijo de namespace se asocia a un directorio raiz, y despues cada fragmento restante del namespace corresponde a un subdirectorio, con el nombre de la clase en el archivo final con extension .php.

<?php

// Namespace: App\Domain\Usuario
// Prefijo:   App\   -> directorio src/
// Archivo:   src/Domain/Usuario.php

namespace App\Domain;

final class Usuario
{
    public function __construct(public readonly string $email) {}
}

La herramienta que aplica esta convencion en la practica es Composer. Declara el prefijo y el directorio en la clave autoload.psr-4 de composer.json y Composer genera el autoloader.

{
    "name": "certidevs/mi-proyecto",
    "require": {
        "php": "^8.4"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    }
}

Tras definir la configuracion se regenera el autoloader con un comando de Composer y ya puedes usar cualquier clase bajo App\ sin hacer require manual.

composer dump-autoload

En el punto de entrada de la aplicacion basta con requerir una sola vez el autoloader de Composer para que todo el namespace este disponible.

<?php

require __DIR__ . "/vendor/autoload.php";

use App\Domain\Usuario;

$u = new Usuario("alicia@example.com");

Antes de PSR-4 existieron convenciones rivales como PSR-0 o mapeos ad-hoc con spl_autoload_register. Hoy PSR-4 es el estandar de facto y todo codigo nuevo deberia seguirlo.

El diagrama muestra la correspondencia entre namespace y directorio.

flowchart TD
    A[Composer autoload.psr-4] --> B["Prefijo App mapea a src"]
    B --> C["App Domain Usuario"]
    C --> D["src/Domain/Usuario.php"]
    B --> E["App Infra Repositorio"]
    E --> F["src/Infra/Repositorio.php"]

PSR-12: estilo de codigo

PSR-12 define una guia extendida de estilo de codigo que unifica la apariencia de cualquier proyecto PHP. Cubre indentacion, espacios alrededor de operadores, uso de llaves, ubicacion de declaraciones, longitud recomendada de lineas y orden de los modificadores.

Los puntos principales que todo desarrollador deberia interiorizar incluyen:

  • 1 - Indentacion de cuatro espacios, nunca tabuladores.
  • 2 - Llaves de clases y metodos en una nueva linea; llaves de estructuras de control en la misma linea que la condicion.
  • 3 - Palabras clave del lenguaje (true, false, null) en minusculas.
  • 4 - Declaracion estricta con declare(strict_types=1); como primera linea ejecutable en cada archivo.
  • 5 - Orden de visibilidad: primero la visibilidad, luego static, luego abstract o final.

Un ejemplo que respeta PSR-12 tiene este aspecto:

<?php

declare(strict_types=1);

namespace App\Domain;

use App\Infra\Registro;

final class Servicio
{
    public function __construct(
        private readonly Registro $registro,
    ) {
    }

    public function procesar(string $entrada): string
    {
        if ($entrada === "") {
            return "vacio";
        }

        return strtoupper($entrada);
    }
}

El estandar se aplica con una herramienta automatica, no a mano. La opcion mas usada es PHP CS Fixer, con un archivo de configuracion que habilita el preset @PSR12.

composer require --dev friendsofphp/php-cs-fixer
vendor/bin/php-cs-fixer fix src

Alternativas muy extendidas son PHP_CodeSniffer con el estandar PSR12, y Laravel Pint (que es un wrapper de PHP CS Fixer con presets orientados al mundo Laravel). Todos comparten la meta de que tu codigo no dependa del criterio personal de cada colaborador.

Integra el formateo en tu pipeline de integracion continua y en un pre-commit hook. Esto elimina discusiones estilisticas durante el code review.

PSR-12 y PHP moderno

PSR-12 se actualiza para dar cabida a las features de PHP 8, como atributos, tipos union o constructor property promotion. Cuando uses estas caracteristicas, sigue conventions como:

  • Los atributos se colocan en una linea propia justo encima del elemento que modifican.
  • Los parametros promovidos del constructor se declaran uno por linea cuando son varios, terminando con coma final.
  • Los tipos union usan | sin espacios: int|string y no int | string.
<?php

final class Producto
{
    public function __construct(
        public readonly string $sku,
        public readonly string $nombre,
        public readonly float $precio,
        public readonly int $stock = 0,
    ) {
    }
}

PSR-3: logger interoperable

PSR-3 especifica la interfaz Psr\Log\LoggerInterface y la biblioteca que implementa una u otra debe respetarla. Gracias a este contrato comun, cualquier biblioteca puede recibir un logger sin acoplarse a una implementacion concreta.

<?php

namespace Psr\Log;

interface LoggerInterface
{
    public function emergency(string|\Stringable $message, array $context = []): void;
    public function alert(string|\Stringable $message, array $context = []): void;
    public function critical(string|\Stringable $message, array $context = []): void;
    public function error(string|\Stringable $message, array $context = []): void;
    public function warning(string|\Stringable $message, array $context = []): void;
    public function notice(string|\Stringable $message, array $context = []): void;
    public function info(string|\Stringable $message, array $context = []): void;
    public function debug(string|\Stringable $message, array $context = []): void;
    public function log($level, string|\Stringable $message, array $context = []): void;
}

Tu codigo depende solo de esa interfaz y acepta cualquier implementacion. La mas conocida es Monolog, que soporta decenas de destinos: ficheros rotativos, Slack, Elasticsearch, Sentry, bases de datos.

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Psr\Log\LoggerInterface;

$logger = new Logger("app");
$logger->pushHandler(new StreamHandler(__DIR__ . "/app.log", Logger::DEBUG));

function procesarPedido(int $id, LoggerInterface $log): void
{
    $log->info("Procesando pedido", ["id" => $id]);
}

procesarPedido(42, $logger);

La inyeccion de LoggerInterface en lugar de Monolog\Logger es lo que hace que tu codigo sea sustituible. Manana puedes cambiar a otra implementacion, o inyectar un fake durante los tests, sin tocar las clases que consumen el logger.

Otros PSR relevantes

PHP-FIG ha publicado decenas de PSR. Ademas de los tres que vertebran esta leccion, conviene conocer al menos:

  • PSR-7: representaciones de mensajes HTTP (request y response). Base de frameworks como Slim y Mezzio.
  • PSR-11: contenedor de inyeccion de dependencias con interfaces ContainerInterface y NotFoundExceptionInterface.
  • PSR-15: middleware HTTP, que encadena handlers sobre PSR-7.
  • PSR-17: fabricas para objetos PSR-7.
  • PSR-18: cliente HTTP interoperable.

Trabajar con PSR donde encaja te libera de decidir reinventar cada pieza. Tu aplicacion se integra con lo que ya existe y se mantiene portable entre frameworks.

Cuando evalues una biblioteca de terceros, mira si declara soporte PSR en su composer.json y en su README. Es un indicador fuerte de calidad y de interoperabilidad.

Adoptar los PSR en un proyecto es un cambio barato con un retorno alto: haces que tu codigo se integre con el ecosistema, que se lea uniforme y que pueda intercambiar piezas sin reescribir todo. En un curso corporativo este alineamiento es el que marca la diferencia entre mantener un sistema durante anos o tirarlo cada dos iteraciones.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, PHP es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de PHP

Explora más contenido relacionado con PHP y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Comprender que es PHP-FIG, aplicar PSR-4 para autoloading con Composer, seguir PSR-12 de estilo de codigo y adoptar PSR-3 para logging desacoplado.