Skip to content

Composer y autoload PSR-4 ​

Composer es el gestor de dependencias de PHP: instala librerías (para enviar correos, generar PDFs, leer Excel...) con un comando y carga tus clases automáticamente. Ningún proyecto PHP profesional moderno se hace sin él, y Laravel depende completamente de Composer.

Concepto ​

Imagina que necesitas enviar correos, crear PDFs y manejar fechas. Sin Composer tendrías que descargar cada librería a mano, descomprimirla, incluir sus archivos en el orden correcto y actualizarla cuando salga una versión nueva. Composer hace todo eso por ti:

  • Gestor de dependencias: lees en composer.json qué librerías usa tu proyecto y Composer las descarga en la carpeta vendor/.
  • Autoloader: genera un archivo vendor/autoload.php que carga cualquier clase justo cuando la usas. Adiós a las listas interminables de require.

Las librerías se publican en Packagist, el "npm" o "tienda de apps" de PHP.

Instalación ​

Windows ​

  1. Descarga el instalador desde getcomposer.org (Composer-Setup.exe).
  2. Durante la instalación te pedirá la ruta de php.exe (por ejemplo C:\xampp\php\php.exe o la de Laragon). Laragon ya trae Composer incluido.
  3. Abre una terminal nueva y comprueba:
powershell
composer --version
# Composer version 2.8.x

Linux / macOS ​

bash
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/local/bin/composer
composer --version

Tu primer proyecto con Composer ​

bash
mkdir mi-proyecto
cd mi-proyecto
composer init

composer init hace unas preguntas (nombre del paquete, descripción, autor...). Puedes aceptar los valores por defecto. Al final se crea un composer.json.

Instalar una librería ​

Vamos a instalar nesbot/carbon, la librería de fechas que usa Laravel:

bash
composer require nesbot/carbon

Esto:

  1. Añade la librería a composer.json.
  2. La descarga (junto con sus propias dependencias) en vendor/.
  3. Crea composer.lock con las versiones exactas instaladas.
  4. Regenera vendor/autoload.php.

Úsala:

php
<?php
// index.php
declare(strict_types=1);

// Una sola línea carga TODAS las librerías instaladas
require __DIR__ . '/vendor/autoload.php';

use Carbon\Carbon;

Carbon::setLocale('es');

$fecha = Carbon::parse('2026-10-18 10:00');
echo $fecha->diffForHumans() . PHP_EOL;            // hace 4 horas
echo $fecha->addDays(10)->translatedFormat('l j \d\e F'), PHP_EOL; // miércoles 28 de octubre

Anatomía de composer.json ​

json
{
    "name": "erick/mi-proyecto",
    "description": "Sistema de reservas para un consultorio",
    "type": "project",
    "require": {
        "php": ">=8.3",
        "nesbot/carbon": "^3.8",
        "phpmailer/phpmailer": "^6.9",
        "vlucas/phpdotenv": "^5.6"
    },
    "require-dev": {
        "phpunit/phpunit": "^11.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "files": [
            "src/helpers.php"
        ]
    },
    "scripts": {
        "test": "phpunit tests",
        "serve": "php -S localhost:8000 -t public"
    }
}
  • require: lo que necesita el proyecto para funcionar en producción.
  • require-dev: herramientas sólo para desarrollo (tests, depuración). Se instalan con composer require --dev paquete.
  • autoload: cómo cargar tus clases (lo vemos ahora).
  • scripts: atajos. composer serve ejecuta el servidor integrado.

Versiones: qué significa ^ y ~ ​

Las versiones siguen el formato MAYOR.MENOR.PARCHE (versionado semántico):

RestricciónAceptaEjemplo
^3.8Desde 3.8.0 hasta antes de 4.0.03.8.1, 3.9, 3.15
~3.8Desde 3.8.0 hasta antes de 3.9.03.8.1, 3.8.7
3.8.2Exactamente esa3.8.2
>=8.3Esa o mayor8.3, 8.4

^ es la opción recomendada: recibes correcciones y mejoras sin cambios que rompan tu código (que sólo llegan en versiones mayores).

Autoload PSR-4 ​

PSR-4 es un estándar que dice: "el namespace de una clase corresponde a su ruta de carpetas". Con la regla "App\\": "src/":

ClaseArchivo
App\Usuariosrc/Usuario.php
App\Modelos\Productosrc/Modelos/Producto.php
App\Http\Controladores\InicioControladorsrc/Http/Controladores/InicioControlador.php

Reglas:

  • Un archivo = una clase.
  • El nombre del archivo es exactamente el nombre de la clase (con mayúsculas) + .php.
  • El namespace sigue la estructura de carpetas.

Ejemplo completo ​

Estructura:

txt
mi-proyecto/
├── composer.json
├── public/
│   └── index.php
├── src/
│   ├── helpers.php
│   ├── Modelos/
│   │   └── Producto.php
│   └── Servicios/
│       └── Calculadora.php
└── vendor/             ← lo crea Composer
php
<?php
// src/Modelos/Producto.php
declare(strict_types=1);

namespace App\Modelos;

final class Producto
{
    public function __construct(
        public readonly string $nombre,
        public readonly float $precio,
    ) {}
}
php
<?php
// src/Servicios/Calculadora.php
declare(strict_types=1);

namespace App\Servicios;

use App\Modelos\Producto;

final class Calculadora
{
    public function __construct(private float $iva = 0.16) {}

    /** @param Producto[] $productos */
    public function total(array $productos): float
    {
        $subtotal = array_sum(array_map(fn (Producto $p) => $p->precio, $productos));
        return round($subtotal * (1 + $this->iva), 2);
    }
}
php
<?php
// src/helpers.php — funciones globales cargadas con "files"
declare(strict_types=1);

function dinero(float $cantidad): string
{
    return '$' . number_format($cantidad, 2);
}

function e(?string $texto): string
{
    return htmlspecialchars($texto ?? '', ENT_QUOTES, 'UTF-8');
}
php
<?php
// public/index.php
declare(strict_types=1);

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

use App\Modelos\Producto;
use App\Servicios\Calculadora;

$productos = [
    new Producto('Teclado', 650),
    new Producto('Mouse', 350),
];

$calc = new Calculadora();
echo 'Total con IVA: ' . dinero($calc->total($productos)); // Total con IVA: $1,160.00

Cada vez que cambies la sección autoload de composer.json, regenera el autoloader:

bash
composer dump-autoload

Con PSR-4 no necesitas ejecutarlo al crear clases nuevas: Composer las encuentra solas siguiendo la regla. Sólo al modificar composer.json.

Error común

Class "App\Modelos\Producto" not found. Revisa, en este orden:

  1. ¿Incluiste vendor/autoload.php?
  2. ¿El namespace del archivo coincide con la carpeta?
  3. ¿El nombre del archivo coincide exactamente con la clase? En Windows producto.php funciona por casualidad, pero en el servidor Linux falla porque distingue mayúsculas.
  4. ¿Ejecutaste composer dump-autoload después de editar composer.json?

Comandos esenciales ​

bash
composer install            # instala lo que dice composer.lock (úsalo al clonar un proyecto)
composer require vendor/pkg # añade una dependencia
composer require --dev vendor/pkg  # dependencia sólo de desarrollo
composer remove vendor/pkg  # quita una dependencia
composer update             # actualiza dentro de las restricciones y reescribe composer.lock
composer update vendor/pkg  # actualiza sólo un paquete
composer outdated           # muestra qué paquetes tienen versiones nuevas
composer audit              # revisa vulnerabilidades conocidas en tus dependencias
composer dump-autoload -o   # autoloader optimizado (para producción)
composer install --no-dev --optimize-autoloader  # instalación de producción

install vs update ​

  • composer install respeta exactamente las versiones de composer.lock. Todo el equipo y el servidor tendrán las mismas versiones.
  • composer update busca versiones nuevas y modifica composer.lock. Hazlo a propósito, en desarrollo, y prueba antes de subir.

Buena práctica

  • Sube a Git composer.json y composer.lock.
  • No subas vendor/ (agrégalo a .gitignore). Se regenera con composer install.
  • Ejecuta composer audit antes de cada entrega a un cliente.

Variables de entorno con phpdotenv ​

Un paquete que usarás en todos tus proyectos: separa las credenciales del código.

bash
composer require vlucas/phpdotenv
env
# .env  (NO se sube a Git)
APP_ENV=local
DB_HOST=127.0.0.1
DB_NAME=tienda
DB_USER=root
DB_PASS=
php
<?php
// config/bootstrap.php
require __DIR__ . '/../vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
// Obliga a que existan estas variables (lanza excepción si falta alguna)
$dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER']);

$dbHost = $_ENV['DB_HOST'];

Más sobre esto en Gestión de secretos.

Subir a hosting compartido sin terminal ​

Muchos hostings compartidos no tienen SSH. Solución:

  1. En tu computadora ejecuta composer install --no-dev --optimize-autoloader.
  2. Sube todo, incluida la carpeta vendor/, por FTP o el administrador de archivos de cPanel.
  3. Asegúrate de que la versión de PHP del hosting sea igual o mayor a la que pide composer.json.

Ejercicios ​

  1. Crea un proyecto con Composer, configura PSR-4 con el namespace Tienda\ apuntando a src/, y crea las clases Tienda\Catalogo\Producto y Tienda\Catalogo\Categoria. Úsalas desde public/index.php.
  2. Instala ramsey/uuid y genera 3 identificadores únicos.
  3. Agrega un script "serve" en composer.json que levante el servidor en public/ y ejecútalo con composer serve.
Ver solución
json
{
    "name": "erick/tienda",
    "require": {
        "php": ">=8.3",
        "ramsey/uuid": "^4.7"
    },
    "autoload": {
        "psr-4": { "Tienda\\": "src/" }
    },
    "scripts": {
        "serve": [
            "Composer\\Config::disableProcessTimeout",
            "php -S localhost:8000 -t public"
        ]
    }
}
php
<?php
// src/Catalogo/Categoria.php
declare(strict_types=1);

namespace Tienda\Catalogo;

final class Categoria
{
    public function __construct(public readonly string $nombre) {}
}
php
<?php
// src/Catalogo/Producto.php
declare(strict_types=1);

namespace Tienda\Catalogo;

final class Producto
{
    public function __construct(
        public readonly string $nombre,
        public readonly Categoria $categoria,
    ) {}
}
php
<?php
// public/index.php
declare(strict_types=1);

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

use Ramsey\Uuid\Uuid;
use Tienda\Catalogo\{Categoria, Producto}; // importación agrupada

$cat = new Categoria('Café');
$p = new Producto('Café de Veracruz', $cat);
echo "{$p->nombre} ({$p->categoria->nombre})<br>";

for ($i = 0; $i < 3; $i++) {
    echo Uuid::uuid4()->toString() . '<br>';
}
bash
composer dump-autoload
composer serve

Resumen ​

  • Composer instala librerías de Packagist en vendor/ y genera vendor/autoload.php.
  • composer.json declara dependencias; composer.lock fija las versiones exactas.
  • PSR-4: el namespace corresponde a la carpeta y el nombre del archivo a la clase.
  • composer install para instalar lo existente, composer require para añadir, composer update sólo a propósito.
  • No subas vendor/ a Git; sí composer.json y composer.lock.
  • En producción: composer install --no-dev --optimize-autoloader y composer audit.

Academia Web — aprende, copia y construye.