Composer, el gestor de dependencias de PHP
En esta lección
Hasta ahora todo el código de tus proyectos lo has escrito tú. En el mundo real casi nadie programa así: para enviar emails, generar PDF, leer configuración o guardar registros de errores se usan librerías que otras personas ya han escrito y probado. Composer es la herramienta que las descarga, las mantiene al día y las carga en tu código. En esta lección aprenderás a instalarlo, a añadir librerías a un proyecto, a entender composer.json y composer.lock, y a usar su autoload para cargar también tus propias clases sin escribir un solo require.
Qué es Composer y qué problema resuelve
Imagina que en la web de una tienda de escalada quieres guardar en un archivo cada pedido y cada error. Podrías escribir tu propio sistema de registros, pero ya existe Monolog, una librería usada por millones de proyectos. Sin Composer tendrías que:
- Descargar el código de Monolog a mano.
- Descargar también las librerías de las que depende Monolog (y las dependencias de esas).
- Escribir un
requirepor cada archivo que uses. - Repetirlo todo cada vez que salga una versión nueva.
Composer hace todo eso por ti. Es un gestor de dependencias: una dependencia es cualquier librería que tu proyecto necesita para funcionar. Tú declaras qué librerías quieres y en qué versión, y Composer calcula qué hay que descargar, lo descarga en una carpeta vendor/ y genera un único archivo que carga todo.
Las librerías salen de Packagist (packagist.org), el repositorio público de paquetes de PHP. Cada paquete tiene un nombre con dos partes, proveedor/paquete: monolog/monolog, vlucas/phpdotenv, phpmailer/phpmailer…
Nota: si vienes de JavaScript, Composer es el equivalente a npm:
composer.jsonhace el papel depackage.jsonyvendor/el denode_modules/. Lo viste en Node.js.
Instalar Composer
Composer es un programa escrito en PHP que se usa desde la terminal. Necesitas tener PHP instalado y accesible desde la línea de comandos (lo preparaste en Servidor local).
- Windows: descarga el instalador
Composer-Setup.exedesde getcomposer.org. Te pedirá la ruta dephp.exe(con XAMPP suele serC:\xampp\php\php.exe) y añadirá Composer alPATH. - macOS: con Homebrew,
brew install composer. - Linux: muchas distribuciones lo tienen en su gestor de paquetes (
sudo apt install composeren Ubuntu o Debian), aunque a veces es una versión antigua. La página de descarga de getcomposer.org explica cómo instalar la última.
Cierra y vuelve a abrir la terminal y comprueba que funciona:
composer --version
Debe mostrar algo como Composer version 2.8.x. Si dice “comando no encontrado”, el instalador no añadió Composer al PATH: reinicia el equipo o revisa la instalación.
Crear el composer.json
Cada proyecto que usa Composer tiene en su carpeta raíz un archivo composer.json: describe el proyecto y lista sus dependencias. Puedes crearlo con un asistente:
cd tienda-escalada
composer init
Te hará unas preguntas (nombre del paquete, descripción, autor, licencia…). Para un proyecto propio puedes aceptar casi todo con Intro y contestar “no” cuando te ofrezca buscar dependencias. El resultado mínimo es algo así:
{
"name": "devschool/tienda-escalada",
"description": "Tienda online de material de escalada",
"type": "project",
"require": {}
}
La sección importante es require: ahí aparecerán las librerías que instales.
Añadir una librería con composer require
Para añadir Monolog al proyecto:
composer require monolog/monolog
Composer hace cuatro cosas:
- Busca en Packagist la última versión compatible con tu PHP.
- La apunta en
composer.json. - Descarga Monolog y sus dependencias (en este caso
psr/log) envendor/. - Crea
composer.locky generavendor/autoload.php.
Tu composer.json queda así:
{
"name": "devschool/tienda-escalada",
"type": "project",
"require": {
"monolog/monolog": "^3.9"
}
}
Y la carpeta del proyecto:
tienda-escalada/
├── composer.json
├── composer.lock
├── index.php
└── vendor/
├── autoload.php
├── composer/
├── monolog/
└── psr/
Qué significa ^3.9
Las librerías siguen el versionado semántico: MAYOR.MENOR.PARCHE. Un cambio de PARCHE arregla errores, uno de MENOR añade cosas sin romper nada, y uno de MAYOR puede romper el código que ya funcionaba. Las restricciones de versión más usadas son:
| Restricción | Acepta | Uso |
|---|---|---|
^3.9 | >=3.9.0 y <4.0.0 | La habitual: actualizaciones seguras, nunca una versión mayor |
~3.9 | >=3.9 y <4.0 | Parecida a ^ con dos cifras |
~3.9.1 | >=3.9.1 y <3.10.0 | Solo parches |
3.9.2 | Exactamente esa | Cuando algo falla con otras versiones |
* | Cualquiera | Evítala: una versión mayor nueva puede romper tu código |
Si no indicas versión, composer require elige por ti una restricción con ^, que es lo recomendable.
Usar la librería: vendor/autoload.php
Composer genera un autoloader: un archivo que, cuando usas una clase que todavía no está cargada, busca su archivo y lo incluye automáticamente. Solo tienes que hacer un require de vendor/autoload.php al principio de tu script:
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Level;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = new Logger('tienda');
$log->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Level::Info));
$log->info('Pedido recibido', ['pedido' => 1042, 'total' => 89.90]);
$log->warning('Stock bajo', ['producto' => 'Pies de gato talla 41', 'quedan' => 1]);
$log->debug('Esto no se guarda: está por debajo de Info');
Tras ejecutarlo, logs/app.log contiene (con tu fecha y hora):
[2026-10-06T10:15:41.667646+00:00] tienda.INFO: Pedido recibido {"pedido":1042,"total":89.9} []
[2026-10-06T10:15:41.668437+00:00] tienda.WARNING: Stock bajo {"producto":"Pies de gato talla 41","quedan":1} []
Fíjate en tres cosas:
useimporta una clase de un espacio de nombres (namespace) para poder escribirLoggeren vez deMonolog\Logger. Los espacios de nombres son como carpetas para clases: evitan que dos librerías con una claseLoggerchoquen entre sí.- El nivel (
Level::Info) filtra lo que se guarda. Los niveles, de menos a más grave, son Debug, Info, Notice, Warning, Error, Critical, Alert y Emergency. En desarrollo puedes guardar desde Debug; en producción, desde Warning o Error. - El segundo argumento es el contexto: un array con datos útiles que se guardan como JSON junto al mensaje.
Consejo: en vez de usar
echoovar_dumppara saber qué pasa en un servidor real (donde nadie ve la pantalla), registra los errores con un logger. Cuando un cliente diga “ayer no pude pagar”, tendrás un archivo donde mirar.
Un ejemplo muy útil: phpdotenv
En la lección de PDO tendrás que conectar con MySQL, y eso exige un usuario y una contraseña. Nunca deben estar escritos en el código: si subes el proyecto a GitHub, cualquiera los verá. La práctica habitual es guardarlos en un archivo .env (de environment, entorno) que no se sube al repositorio, y leerlo con la librería vlucas/phpdotenv:
composer require vlucas/phpdotenv
El archivo .env, en la raíz del proyecto:
APP_ENTORNO=desarrollo
DB_HOST=localhost
DB_NAME=tienda
DB_USER=root
DB_PASS="clave con espacios"
Y el código que lo carga:
<?php
require __DIR__ . '/vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER'])->notEmpty();
echo $_ENV['DB_HOST'], "\n";
echo $_ENV['DB_PASS'], "\n";
echo $_ENV['APP_ENTORNO'] ?? 'produccion', "\n";
// localhost
// clave con espacios
// desarrollo
createImmutable(__DIR__)indica la carpeta donde está el.env. “Inmutable” significa que no sobrescribe variables de entorno que ya existan en el servidor, lo que permite que en producción el hosting defina las suyas.load()lee el archivo y rellena$_ENV.required(...)->notEmpty()lanza una excepción si falta alguna variable o está vacía. Así el fallo aparece al arrancar, con un mensaje claro, y no más tarde con un error de conexión confuso.
Junto a .env se suele subir un .env.example con las mismas claves pero sin valores reales. Quien descargue el proyecto lo copia como .env y pone sus datos.
Autoload PSR-4 para tus propias clases
El autoloader de Composer no solo sirve para las librerías: también puede cargar tus clases. Para eso sigue una norma llamada PSR-4, que relaciona el espacio de nombres de cada clase con la carpeta donde está su archivo. Las reglas son sencillas:
- Cada clase va en su propio archivo, que se llama igual que la clase:
ProductoenProducto.php. - Eliges un espacio de nombres raíz para tu proyecto (por ejemplo
Tienda) y lo asocias a una carpeta (normalmentesrc/). - Cada subespacio de nombres es una subcarpeta:
Tienda\Modelo\Productoestará ensrc/Modelo/Producto.php.
Lo indicas en composer.json con la sección autoload:
{
"name": "devschool/tienda-escalada",
"type": "project",
"require": {
"monolog/monolog": "^3.9",
"vlucas/phpdotenv": "^5.6"
},
"autoload": {
"psr-4": {
"Tienda\\": "src/"
}
}
}
La barra invertida va doblada porque en JSON \ se escapa, y el espacio de nombres termina siempre en \\. Después de cambiar la sección autoload, regenera el autoloader:
composer dump-autoload
Ahora crea las clases. src/Precio.php:
<?php
declare(strict_types=1);
namespace Tienda;
class Precio
{
public static function conIva(float $base, float $iva = 21): float
{
return round($base * (1 + $iva / 100), 2);
}
}
src/Modelo/Producto.php:
<?php
declare(strict_types=1);
namespace Tienda\Modelo;
class Producto
{
public function __construct(
public string $nombre,
public float $precio,
public int $stock = 0,
) {}
}
Y index.php, en la raíz, las usa sin incluir sus archivos:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use Tienda\Precio;
use Tienda\Modelo\Producto;
$cuerda = new Producto('Cuerda 60 m', 120.0, 3);
echo $cuerda->nombre, ': ', Precio::conIva($cuerda->precio), " €\n";
// Cuerda 60 m: 145.2 €
Cuando PHP encuentra Tienda\Modelo\Producto, el autoloader quita el prefijo Tienda\, cambia las barras invertidas por barras de carpeta y añade .php: carga src/Modelo/Producto.php. Si añades más clases siguiendo la norma, no hace falta volver a ejecutar dump-autoload; solo cuando cambias la sección autoload del composer.json.
La estructura completa del proyecto queda así:
tienda-escalada/
├── composer.json
├── composer.lock
├── .env
├── .env.example
├── .gitignore
├── index.php
├── logs/
├── src/
│ ├── Precio.php
│ └── Modelo/
│ └── Producto.php
└── vendor/
Las clases, los constructores con promoción de propiedades y static se explican a fondo en Clases y objetos.
composer.lock, vendor/ y Git
Aquí está la parte que más se lía al principio. Hay dos archivos de dependencias y cada uno tiene su función:
composer.jsondice lo que aceptas: “Monolog 3.9 o cualquier 3.x posterior”.composer.lockdice lo que se instaló exactamente: “Monolog 3.9.0, psr/log 3.0.2”, con la dirección de descarga de cada uno.
Gracias al .lock, todas las personas del equipo y el servidor de producción tienen las mismas versiones exactas, aunque instalen meses después. Por eso:
| Archivo o carpeta | ¿Se sube a Git? | Motivo |
|---|---|---|
composer.json | Sí | Lista de dependencias del proyecto |
composer.lock | Sí (en proyectos y aplicaciones) | Garantiza las mismas versiones en todas partes |
vendor/ | No | Se regenera con composer install; puede pesar mucho |
.env | No | Contiene contraseñas |
.env.example | Sí | Sirve de plantilla |
El archivo .gitignore del proyecto:
/vendor/
.env
/logs/*.log
Cuando alguien clona el repositorio, no tiene vendor/. Lo crea con:
composer install
install frente a update
Son los dos comandos que más se confunden:
composer installleecomposer.locke instala esas versiones exactas. Es el que usas al clonar un proyecto y al desplegarlo en el servidor. Si no hay.lock, se comporta comoupdate.composer updateignora el.lock, busca las versiones más nuevas que permitecomposer.json, las instala y reescribe el.lock. Úsalo cuando quieras actualizar a propósito, y prueba la web después.
Puedes actualizar una sola librería con composer update monolog/monolog.
Otros comandos útiles
| Comando | Qué hace |
|---|---|
composer require paquete | Añade una dependencia |
composer require --dev paquete | Añade una dependencia solo para desarrollo (en require-dev) |
composer remove paquete | Quita una dependencia y borra sus archivos |
composer show | Lista los paquetes instalados y sus versiones |
composer outdated | Muestra cuáles tienen versiones más nuevas |
composer audit | Busca vulnerabilidades conocidas en tus dependencias |
composer dump-autoload | Regenera el autoloader |
composer install --no-dev --optimize-autoloader | Instalación para producción |
Las dependencias de desarrollo son herramientas que solo necesitas mientras programas, como PHPUnit para las pruebas automáticas o PHPStan para analizar el código. Van en una sección aparte, require-dev, y en producción se omiten con --no-dev.
También puedes definir scripts, atajos con nombre para comandos que repites:
{
"scripts": {
"revisar": "php -l index.php"
}
}
Y lanzarlo con composer revisar (en este caso, comprueba la sintaxis de index.php).
Cuidado: antes de instalar un paquete, mira en Packagist cuántas descargas tiene, cuándo se actualizó por última vez y si su repositorio está activo. Cada dependencia es código de otra persona que se ejecuta en tu servidor. Si un paquete lleva años abandonado, busca una alternativa.
Errores frecuentes
- Olvidar
require __DIR__ . '/vendor/autoload.php': apareceClass "Monolog\Logger" not found. Eserequireva al principio de cada punto de entrada (index.php, por ejemplo). - Subir
vendor/a Git: llena el repositorio de miles de archivos ajenos. Añádelo a.gitignorey usacomposer install. - No subir
composer.lock: cada persona acaba con versiones distintas y aparecen errores “que en mi ordenador no pasan”. - Usar
composer updateen el servidor: puede instalar versiones que nunca has probado. En producción, siemprecomposer install. - Nombres que no siguen PSR-4: si la clase es
Productopero el archivo se llamaproducto.php, en Windows funcionará y en un servidor Linux no, porque distingue mayúsculas. El archivo debe llamarse exactamente igual que la clase. - Cambiar
autoloady no ejecutarcomposer dump-autoload: el autoloader sigue con la configuración antigua y no encuentra tus clases. - Subir el
.env: tus contraseñas quedan públicas. Si te ha pasado, cámbialas inmediatamente, aunque borres el archivo después.
Resumen
| Concepto | Qué recordar |
|---|---|
| Composer | Gestor de dependencias de PHP; los paquetes salen de Packagist |
composer.json | Lo que necesita el proyecto y con qué versiones (^3.9) |
composer.lock | Versiones exactas instaladas; se sube a Git |
vendor/ | Código descargado; no se sube a Git |
composer require x/y | Añade una librería |
composer install | Instala lo que dice el .lock (al clonar o desplegar) |
composer update | Busca versiones nuevas y reescribe el .lock |
vendor/autoload.php | Un único require que carga todas las clases |
| PSR-4 | "Tienda\\": "src/": Tienda\Modelo\Producto está en src/Modelo/Producto.php |
.env + phpdotenv | Configuración y contraseñas fuera del código |
En la siguiente lección juntarás todo lo aprendido en el curso para construir una aplicación completa: Proyecto: libro de visitas.
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.