Interfaces
Una interface es un contrato que define que metodos debe tener una clase, sin especificar como implementarlos. A diferencia de las clases, puedes implementar multiples interfaces.
¿Que es una interface?
Una interface define firmas de metodos que las clases deben implementar. No contiene logica, solo la estructura:
<?php
declare(strict_types=1);
interface Imprimible
{
public function imprimir(): string;
}
class Documento implements Imprimible
{
private string $contenido;
public function __construct(string $contenido)
{
$this->contenido = $contenido;
}
public function imprimir(): string
{
return "Documento: {$this->contenido}";
}
}
class Factura implements Imprimible
{
private float $total;
public function __construct(float $total)
{
$this->total = $total;
}
public function imprimir(): string
{
return "Factura: \${$this->total}";
}
}
$doc = new Documento('Contrato de servicios');
$factura = new Factura(199.99);
echo $doc->imprimir(); // Documento: Contrato de servicios
echo $factura->imprimir(); // Factura: $199.99
Implementar multiples interfaces
Una clase puede implementar varias interfaces, superando la limitacion de la herencia simple:
<?php
declare(strict_types=1);
interface Guardable
{
public function guardar(): bool;
}
interface Exportable
{
public function exportar(string $formato): string;
}
class Reporte implements Guardable, Exportable
{
private string $titulo;
private string $contenido;
public function __construct(string $titulo, string $contenido)
{
$this->titulo = $titulo;
$this->contenido = $contenido;
}
public function guardar(): bool
{
// Logica para guardar en base de datos
return true;
}
public function exportar(string $formato): string
{
return match ($formato) {
'json' => json_encode(['titulo' => $this->titulo, 'contenido' => $this->contenido]),
'csv' => "{$this->titulo},{$this->contenido}",
default => $this->contenido,
};
}
}
$reporte = new Reporte('Ventas Q1', 'Total: $50,000');
$reporte->guardar();
echo $reporte->exportar('json');
Los nombres de interfaces suelen ser
adjetivos (Imprimible,
Guardable) o sustantivos
con sufijo "able/ible" que describen una
capacidad.
Type hinting con interfaces
Las interfaces permiten escribir codigo flexible que trabaja con cualquier objeto que cumpla el contrato:
<?php
declare(strict_types=1);
interface Logger
{
public function log(string $mensaje): void;
}
class FileLogger implements Logger
{
public function log(string $mensaje): void
{
echo "[Archivo] $mensaje\n";
}
}
class DatabaseLogger implements Logger
{
public function log(string $mensaje): void
{
echo "[Base de datos] $mensaje\n";
}
}
class Aplicacion
{
private Logger $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger; // Acepta cualquier Logger
}
public function ejecutar(): void
{
$this->logger->log('Aplicacion iniciada');
}
}
$app1 = new Aplicacion(new FileLogger());
$app1->ejecutar(); // [Archivo] Aplicacion iniciada
$app2 = new Aplicacion(new DatabaseLogger());
$app2->ejecutar(); // [Base de datos] Aplicacion iniciada
Interface vs Clase abstracta
| Caracteristica | Interface | Clase abstracta |
|---|---|---|
| Metodos | Solo firmas | Abstractos y concretos |
| Propiedades | Solo constantes | Cualquier tipo |
| Herencia/Implementacion | Multiple | Simple |
| Uso | Definir capacidades | Compartir codigo comun |
Ejemplo practico: Sistema de notificaciones
<?php
declare(strict_types=1);
interface Notificador
{
public function enviar(string $destinatario, string $mensaje): bool;
}
class EmailNotificador implements Notificador
{
public function enviar(string $destinatario, string $mensaje): bool
{
echo "Email a $destinatario: $mensaje\n";
return true;
}
}
class SMSNotificador implements Notificador
{
public function enviar(string $destinatario, string $mensaje): bool
{
echo "SMS a $destinatario: $mensaje\n";
return true;
}
}
class ServicioNotificaciones
{
/** @var Notificador[] */
private array $notificadores = [];
public function agregar(Notificador $notificador): void
{
$this->notificadores[] = $notificador;
}
public function notificarTodos(string $destinatario, string $mensaje): void
{
foreach ($this->notificadores as $notificador) {
$notificador->enviar($destinatario, $mensaje);
}
}
}
$servicio = new ServicioNotificaciones();
$servicio->agregar(new EmailNotificador());
$servicio->agregar(new SMSNotificador());
$servicio->notificarTodos('usuario@email.com', 'Tu pedido ha sido enviado');
// Email a usuario@email.com: Tu pedido ha sido enviado
// SMS a usuario@email.com: Tu pedido ha sido enviado
Ejercicios
Ejercicio 1: Reproductor multimedia
Crea una interface
Reproducible con metodos
reproducir(),
pausar() y
detener(). Implementa
clases Cancion y
Video.
Ver solucion
<?php
declare(strict_types=1);
interface Reproducible
{
public function reproducir(): string;
public function pausar(): string;
public function detener(): string;
}
class Cancion implements Reproducible
{
private string $titulo;
private string $artista;
public function __construct(string $titulo, string $artista)
{
$this->titulo = $titulo;
$this->artista = $artista;
}
public function reproducir(): string
{
return "Reproduciendo cancion: {$this->titulo} - {$this->artista}";
}
public function pausar(): string
{
return "Cancion pausada: {$this->titulo}";
}
public function detener(): string
{
return "Cancion detenida: {$this->titulo}";
}
}
class Video implements Reproducible
{
private string $titulo;
private int $duracion;
public function __construct(string $titulo, int $duracion)
{
$this->titulo = $titulo;
$this->duracion = $duracion;
}
public function reproducir(): string
{
return "Reproduciendo video: {$this->titulo} ({$this->duracion}s)";
}
public function pausar(): string
{
return "Video pausado: {$this->titulo}";
}
public function detener(): string
{
return "Video detenido: {$this->titulo}";
}
}
$cancion = new Cancion('Bohemian Rhapsody', 'Queen');
$video = new Video('Tutorial PHP', 600);
echo $cancion->reproducir(); // Reproduciendo cancion: Bohemian Rhapsody - Queen
echo $video->reproducir(); // Reproduciendo video: Tutorial PHP (600s)
Ejercicio 2: Carrito de compras
Crea Vendible con
getPrecio(): float y
getNombre(): string.
Implementa Producto y
Servicio. Crea un carrito
que acepte cualquier
Vendible.
Ver solucion
<?php
declare(strict_types=1);
interface Vendible
{
public function getPrecio(): float;
public function getNombre(): string;
}
class Producto implements Vendible
{
private string $nombre;
private float $precio;
public function __construct(string $nombre, float $precio)
{
$this->nombre = $nombre;
$this->precio = $precio;
}
public function getPrecio(): float
{
return $this->precio;
}
public function getNombre(): string
{
return $this->nombre;
}
}
class Servicio implements Vendible
{
private string $nombre;
private float $tarifaHora;
private int $horas;
public function __construct(string $nombre, float $tarifaHora, int $horas)
{
$this->nombre = $nombre;
$this->tarifaHora = $tarifaHora;
$this->horas = $horas;
}
public function getPrecio(): float
{
return $this->tarifaHora * $this->horas;
}
public function getNombre(): string
{
return $this->nombre;
}
}
class Carrito
{
/** @var Vendible[] */
private array $items = [];
public function agregar(Vendible $item): void
{
$this->items[] = $item;
}
public function getTotal(): float
{
$total = 0;
foreach ($this->items as $item) {
$total += $item->getPrecio();
}
return $total;
}
}
$carrito = new Carrito();
$carrito->agregar(new Producto('Laptop', 999.99));
$carrito->agregar(new Servicio('Consultoria', 50, 3));
echo $carrito->getTotal(); // 1149.99
Ejercicio 3: Autenticacion
Crea Autenticable con
login(string $password): bool
y logout(): void.
Implementa UsuarioNormal y
UsuarioAdmin (el admin
requiere codigo 2FA adicional).
Ver solucion
<?php
declare(strict_types=1);
interface Autenticable
{
public function login(string $password): bool;
public function logout(): void;
}
class UsuarioNormal implements Autenticable
{
private string $email;
private string $passwordHash;
private bool $logueado = false;
public function __construct(string $email, string $password)
{
$this->email = $email;
$this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
}
public function login(string $password): bool
{
if (password_verify($password, $this->passwordHash)) {
$this->logueado = true;
return true;
}
return false;
}
public function logout(): void
{
$this->logueado = false;
echo "Usuario {$this->email} deslogueado\n";
}
}
class UsuarioAdmin implements Autenticable
{
private string $email;
private string $passwordHash;
private string $codigo2FA;
private bool $logueado = false;
public function __construct(string $email, string $password, string $codigo2FA)
{
$this->email = $email;
$this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
$this->codigo2FA = $codigo2FA;
}
public function login(string $password): bool
{
return false; // Admin requiere 2FA
}
public function loginCon2FA(string $password, string $codigo): bool
{
if (password_verify($password, $this->passwordHash) && $codigo === $this->codigo2FA) {
$this->logueado = true;
return true;
}
return false;
}
public function logout(): void
{
$this->logueado = false;
echo "Admin {$this->email} deslogueado\n";
}
}
$usuario = new UsuarioNormal('user@email.com', 'password123');
$admin = new UsuarioAdmin('admin@email.com', 'admin123', '123456');
$usuario->login('password123'); // true
$admin->loginCon2FA('admin123', '123456'); // true
¿Has encontrado un error o tienes una sugerencia para mejorar esta leccion?
Escribenos¿Te está gustando el curso?
Tenemos cursos premium con proyectos reales y soporte personalizado.
Descubrir cursos premium