Curso de PHP
Interfaces en PHP: contratos entre clases
Por Víctor Peña · Publicado el

Hola, ¿cómo están? Continuando con el curso de PHP, hoy veremos las interfaces. Si tuviera que señalar el concepto que más separa el código de aficionado del profesional, sería este.
¡Empecemos!
Qué es una interfaz
Una interfaz es un contrato: una lista de métodos que una clase se compromete a tener, sin decir nada sobre cómo los implementa.
<?php
interface Exportable
{
public function exportar(): string;
}
Eso es todo. Sin cuerpos, sin propiedades, sin constructor. Solo la promesa: «quien implemente esto tendrá un método exportar() que devuelve un texto».
Implementar una interfaz
<?php
class Factura implements Exportable
{
public function exportar(): string
{
return "Factura generada en PDF";
}
}
class ReporteVentas implements Exportable
{
public function exportar(): string
{
return "Reporte generado en Excel";
}
}
Si una clase declara implements Exportable y no define exportar(), PHP falla de inmediato. El contrato se cumple o el código no arranca.
Para qué sirve realmente
La utilidad no está en la interfaz misma, sino en poder escribir código que dependa del contrato y no de una clase concreta:
<?php
function descargar(Exportable $documento): void
{
echo $documento->exportar();
}
descargar(new Factura());
descargar(new ReporteVentas());
descargar() funciona con cualquier cosa que sea exportable. Y aquí está lo importante: funcionará también con las clases que escribas dentro de dos años, sin tocar una línea de esta función.
La gran ventaja: varias interfaces a la vez
Como vimos en herencia, una clase solo puede extender una clase. Pero puede implementar todas las interfaces que quiera:
<?php
interface Exportable
{
public function exportar(): string;
}
interface Imprimible
{
public function imprimir(): void;
}
interface Archivable
{
public function archivar(): bool;
}
class Factura implements Exportable, Imprimible, Archivable
{
public function exportar(): string { return "PDF"; }
public function imprimir(): void { echo "Imprimiendo..."; }
public function archivar(): bool { return true; }
}
Esto resuelve el problema de la herencia múltiple sin sus ambigüedades. Una factura es un documento (herencia) y además puede ser exportada, impresa y archivada (interfaces).
Fíjate en el matiz del lenguaje: la herencia describe qué es algo; la interfaz, qué puede hacer. Por eso muchas interfaces terminan en «-able».
Interfaz o clase abstracta
Ya lo vimos en la lección anterior, pero conviene repetir la regla porque es la duda más frecuente:
- Clase abstracta si las clases comparten código y están emparentadas.
- Interfaz si solo comparten una capacidad, sin relación entre ellas.
Y la señal decisiva: si necesitas que una clase cumpla dos contratos distintos, tiene que ser con interfaces.
Constantes en interfaces
Una interfaz puede definir constantes, que quedan disponibles en todas las clases que la implementen:
<?php
interface EstadoPedido
{
const PENDIENTE = 'pendiente';
const PAGADO = 'pagado';
const ENVIADO = 'enviado';
}
class Pedido implements EstadoPedido
{
private string $estado = self::PENDIENTE;
}
Lo que no puede tener son propiedades. Una interfaz describe comportamiento, no datos.
Herencia entre interfaces
Una interfaz puede extender otra, e incluso varias:
<?php
interface Legible
{
public function leer(): string;
}
interface Escribible
{
public function escribir(string $contenido): bool;
}
interface Archivo extends Legible, Escribible
{
public function existe(): bool;
}
Quien implemente Archivo deberá definir los tres métodos.
Interfaces nativas de PHP
PHP trae varias interfaces que hacen que tus objetos se integren con el lenguaje. Ya vimos algunas:
<?php
class Coleccion implements IteratorAggregate, Countable, JsonSerializable
{
private array $items = [];
public function getIterator(): ArrayIterator
{
return new ArrayIterator($this->items);
}
public function count(): int
{
return count($this->items);
}
public function jsonSerialize(): array
{
return $this->items;
}
}
$c = new Coleccion();
foreach ($c as $item) { } // gracias a IteratorAggregate
echo count($c); // gracias a Countable
echo json_encode($c); // gracias a JsonSerializable
Las más útiles en el día a día:
| Interfaz | Qué permite |
|---|---|
Countable |
Usar count() sobre el objeto |
IteratorAggregate |
Recorrerlo con foreach |
JsonSerializable |
Controlar cómo se convierte a JSON |
ArrayAccess |
Acceder con corchetes: $obj['clave'] |
Stringable |
Convertirlo a texto con (string) |
El uso profesional: inyección de dependencias
Aquí está la razón por la que las interfaces importan tanto en código real.
Compara estas dos versiones:
<?php
// Acoplada: depende de una clase concreta
class ServicioDePedidos
{
public function confirmar(int $id): void
{
$mailer = new MailerSmtp(); // atado a esta implementación
$mailer->enviar("Pedido $id confirmado");
}
}
<?php
// Desacoplada: depende del contrato
interface Mailer
{
public function enviar(string $mensaje): bool;
}
class ServicioDePedidos
{
public function __construct(
private Mailer $mailer,
) {}
public function confirmar(int $id): void
{
$this->mailer->enviar("Pedido $id confirmado");
}
}
En la segunda versión puedes pasarle un MailerSmtp en producción, un MailerDePrueba al hacer pruebas, o cambiar mañana a otro proveedor sin tocar ServicioDePedidos.
Eso es lo que hace que un sistema sea mantenible, y es exactamente el mecanismo sobre el que están construidos Laravel y Symfony.
Aquí encajan también las clases anónimas que vimos: crear un Mailer de prueba al vuelo, sin archivo aparte.
Comprobar el contrato
<?php
$factura = new Factura();
var_dump($factura instanceof Exportable); // true
var_dump($factura instanceof Imprimible); // true
instanceof funciona con interfaces igual que con clases, y es lo que permite verificar capacidades antes de usarlas.
Cuándo no hacen falta
Seamos honestos: no toda clase necesita una interfaz. Crear una interfaz que implementa una sola clase, y que nunca va a tener otra, es ceremonia sin beneficio.
La interfaz se justifica cuando:
- Hay o va a haber más de una implementación.
- Quieres poder sustituir la implementación en pruebas.
- Estás definiendo un límite entre partes del sistema.
Si nada de eso aplica, una clase normal está bien.
Errores comunes
- Declarar métodos con cuerpo dentro de una interfaz. No se puede.
- Poner propiedades. Solo constantes.
- Usar modificadores distintos de
public. Todos los métodos de una interfaz lo son. - Cambiar la firma al implementar.
- Crear interfaces para todo, incluso donde nunca habrá una segunda implementación.
Para cerrar
Una interfaz es una promesa sobre lo que una clase sabe hacer. Su valor está en que permite escribir código contra el contrato y no contra la implementación, que es lo que te deja cambiar piezas sin romper el resto.
Si te llevas una idea: depende de interfaces, no de clases concretas, siempre que haya más de una forma posible de hacer algo.
En la siguiente lección veremos los namespaces.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp