Leccion 63 de 75 12 min de lectura

Estandares PSR

Los PSR (PHP Standard Recommendations) son estandares desarrollados por el PHP-FIG (Framework Interoperability Group) para que todo el codigo PHP siga las mismas convenciones. Seguir estos estandares hace tu codigo mas legible y compatible con las librerias del ecosistema PHP.

¿Qué es el PHP-FIG?

El PHP Framework Interoperability Group es un grupo formado por representantes de los principales frameworks y proyectos PHP (Laravel, Symfony, Drupal, etc.). Su objetivo es crear estandares comunes para que el codigo sea interoperable entre proyectos.

Los PSR mas importantes para el dia a dia son:

  • PSR-1: Estándar básico de codificación
  • PSR-4: Autoloading (ya lo vimos en la leccion de Composer)
  • PSR-12: Guia de estilo extendida

PSR-1: Estandar basico

Define las reglas fundamentales que todo codigo PHP debe seguir:

Archivos

  • Solo usar las etiquetas <?php o <?=
  • Codificacion UTF-8 sin BOM
  • Un archivo debe declarar símbolos (clases, funciones) O ejecutar código, no ambos
PHP
<?php
// INCORRECTO: mezcla declaracion con ejecucion
declare(strict_types=1);

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

// Esto no deberia estar aqui
$usuario = new Usuario('Ana');
echo $usuario->nombre;
PHP
<?php
// CORRECTO: archivo src/Usuario.php (solo declaracion)
declare(strict_types=1);

namespace App;

class Usuario
{
    public function __construct(
        public readonly string $nombre
    ) {}
}
PHP
<?php
// CORRECTO: archivo index.php (solo ejecucion)
declare(strict_types=1);

require_once 'vendor/autoload.php';

use App\Usuario;

$usuario = new Usuario('Ana');
echo $usuario->nombre;

Nombres

  • Clases: PascalCase (MiClase, ControladorUsuario)
  • Constantes de clase: MAYUSCULAS_CON_GUIONES (MAX_INTENTOS)
  • Metodos: camelCase (obtenerNombre, calcularTotal)
PHP
<?php

declare(strict_types=1);

namespace App\Servicios;

class GestorPedidos  // PascalCase
{
    public const MAX_ITEMS_POR_PEDIDO = 100;  // MAYUSCULAS

    public function crearPedido(array $items): Pedido  // camelCase
    {
        // ...
    }

    public function calcularTotal(Pedido $pedido): float
    {
        // ...
    }
}

PSR-12: Guia de estilo

PSR-12 extiende PSR-1 con reglas detalladas sobre formato y estilo:

Estructura de archivos

PHP
<?php

// 1. Etiqueta de apertura
// 2. declare (si lo hay)
declare(strict_types=1);

// 3. namespace
namespace App\Controladores;

// 4. imports (use) - uno por linea, ordenados
use App\Entidades\Usuario;
use App\Repositorios\UsuarioRepositorio;
use App\Servicios\EmailService;

// 5. Declaracion de clase
class UsuarioControlador
{
    // Contenido...
}

Indentacion y lineas

  • Usar 4 espacios (no tabs)
  • Maximo 120 caracteres por linea (recomendado 80)
  • Una linea en blanco al final del archivo
  • No dejar espacios en blanco al final de las lineas

Llaves y espacios

PHP
<?php

declare(strict_types=1);

namespace App;

// Llave de apertura en nueva linea para clases
class Calculadora
{
    // Llave de apertura en nueva linea para metodos
    public function sumar(int $a, int $b): int
    {
        return $a + $b;
    }

    // Estructuras de control: llave en la misma linea
    public function esPar(int $numero): bool
    {
        if ($numero % 2 === 0) {
            return true;
        } else {
            return false;
        }
    }

    // Ejemplo con switch
    public function obtenerDia(int $numero): string
    {
        switch ($numero) {
            case 1:
                return 'Lunes';
            case 2:
                return 'Martes';
            default:
                return 'Desconocido';
        }
    }
}

Metodos y funciones

PHP
<?php

declare(strict_types=1);

namespace App;

class Servicio
{
    // Sin espacio entre nombre de metodo y parentesis
    // Espacio despues de cada coma en parametros
    public function procesar(string $dato, int $limite): array
    {
        // ...
    }

    // Parametros en multiples lineas cuando son muchos
    public function crearUsuario(
        string $nombre,
        string $email,
        string $password,
        ?string $telefono = null
    ): Usuario {
        // ...
    }

    // Visibilidad siempre explicita
    private function metodoPrivado(): void
    {
        // ...
    }
}

Orden de visibilidad

PHP
<?php

declare(strict_types=1);

namespace App;

// Orden de modificadores: abstract/final, visibilidad, static, readonly
abstract class ClaseBase
{
    // Primero constantes
    public const VERSION = '1.0';
    private const LIMITE = 100;

    // Luego propiedades
    public readonly string $id;
    protected static int $contador = 0;
    private array $datos = [];

    // Finalmente metodos
    abstract public function procesar(): void;

    final protected static function incrementar(): void
    {
        self::$contador++;
    }
}

Herramientas automaticas

No tienes que verificar manualmente que tu codigo cumple PSR-12. Existen herramientas que lo hacen automaticamente:

PHP-CS-Fixer

Bash
# Instalar como dependencia de desarrollo
composer require --dev friendsofphp/php-cs-fixer

# Ejecutar para ver problemas
./vendor/bin/php-cs-fixer fix src --dry-run --diff

# Ejecutar para corregir automaticamente
./vendor/bin/php-cs-fixer fix src

Crea un archivo .php-cs-fixer.php en la raiz del proyecto:

PHP
<?php

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__ . '/src')
    ->in(__DIR__ . '/tests');

return (new PhpCsFixer\Config())
    ->setRules([
        '@PSR12' => true,
        'strict_param' => true,
        'declare_strict_types' => true,
    ])
    ->setFinder($finder)
    ->setRiskyAllowed(true);

PHP_CodeSniffer

Bash
# Instalar
composer require --dev squizlabs/php_codesniffer

# Verificar codigo contra PSR-12
./vendor/bin/phpcs --standard=PSR12 src

# Corregir automaticamente lo posible
./vendor/bin/phpcbf --standard=PSR12 src

PSR-4: Recordatorio

Ya vimos PSR-4 en detalle en la leccion de Composer. Es el estandar para autoloading que mapea namespaces a directorios:

JSON
{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

App\Servicios\EmailServicesrc/Servicios/EmailService.php

Ejercicios

Ejercicio 1: Corregir codigo

El siguiente codigo tiene varios errores de estilo segun PSR-12. Identifica y corrige al menos 5 problemas:

PHP
<?php
namespace app\servicios;
use App\Usuario;
use App\Email;
class gestorUsuarios{
    const max_usuarios=100;
    function CrearUsuario($nombre,$email){
        if($nombre==''){
            return null;
        }
        else{
            return new Usuario($nombre,$email);
        }
    }
}
Ver solucion
PHP
<?php

declare(strict_types=1);  // 1. Faltaba declare

namespace App\Servicios;  // 2. Namespace en PascalCase

use App\Email;    // 3. Linea en blanco antes de use
use App\Usuario;  // 4. Un use por linea, ordenados

class GestorUsuarios  // 5. Clase en PascalCase, llave en nueva linea
{
    public const MAX_USUARIOS = 100;  // 6. Visibilidad, MAYUSCULAS

    public function crearUsuario(string $nombre, string $email): ?Usuario  // 7. Visibilidad, camelCase, tipos, espacios
    {
        if ($nombre === '') {  // 8. Espacio despues de if, ===
            return null;
        }

        return new Usuario($nombre, $email);  // 9. Sin else innecesario
    }
}

Problemas corregidos:

  1. Faltaba declare(strict_types=1)
  2. Namespace debe ser PascalCase: App\Servicios
  3. Linea en blanco entre namespace y use
  4. Use en lineas separadas y ordenados alfabeticamente
  5. Clase en PascalCase, llave de apertura en nueva linea
  6. Constante con visibilidad explicita y MAYUSCULAS
  7. Metodo con visibilidad, camelCase, type hints y espacios despues de comas
  8. Espacio entre if y parentesis, comparacion estricta
  9. Else innecesario eliminado (early return)

Ejercicio 2: Estructura de clase

Crea una clase Producto en el namespace App\Entidades que cumpla PSR-12. Debe tener:

  • Una constante IVA con valor 0.21
  • Propiedades nombre (string) y precio (float)
  • Constructor con property promotion
  • Metodo calcularPrecioConIva
Ver solucion
PHP
<?php

declare(strict_types=1);

namespace App\Entidades;

class Producto
{
    public const IVA = 0.21;

    public function __construct(
        public readonly string $nombre,
        public readonly float $precio
    ) {}

    public function calcularPrecioConIva(): float
    {
        return $this->precio * (1 + self::IVA);
    }
}

Ejercicio 3: Configurar PHP-CS-Fixer

Escribe un archivo .php-cs-fixer.php que:

  • Use las reglas de PSR-12
  • Busque archivos en src y tests
  • Exija declare(strict_types=1)
Ver solucion
PHP
<?php

declare(strict_types=1);

$finder = PhpCsFixer\Finder::create()
    ->in(__DIR__ . '/src')
    ->in(__DIR__ . '/tests');

return (new PhpCsFixer\Config())
    ->setRules([
        '@PSR12' => true,
        'declare_strict_types' => true,
        'ordered_imports' => ['sort_algorithm' => 'alpha'],
        'no_unused_imports' => true,
    ])
    ->setFinder($finder)
    ->setRiskyAllowed(true);

Te está gustando el curso?

Tenemos cursos premium con proyectos reales y soporte personalizado.

Descubrir cursos premium