Introducción: por qué SOLID es la base del código PHP de calidad
Todo desarrollador de PHP, tarde o temprano, se enfrenta a una situación en la que un pequeño proyecto se convierte en "código espagueti". Las clases se vuelven sobrecargadas, los cambios en una parte del sistema rompen otra, y las pruebas se convierten en una pesadilla. Precisamente para resolver estos problemas, Robert Martin (tío Bob) formuló los cinco principios SOLID. Estos principios no son teoría abstracta, sino herramientas prácticas que ayudan a crear código PHP flexible, mantenible y comprobable.
En este artículo, analizaremos cada principio SOLID: desde la teoría hasta ejemplos reales en PHP 8.x. Aprenderá cómo aplicarlos en el desarrollo diario y qué antipatrones debe evitar.
1. Single Responsibility Principle (SRP) — principio de responsabilidad única
Teoría
El principio establece: una clase debe tener solo una razón para cambiar. Esto significa que cada clase debe ser responsable de una funcionalidad o lógica de negocio específica.
Antipatrón (violación de SRP)
<?phpclass OrderProcessor { public function process(Order $order): void { // 1. Validación del pedido if (empty($order->getItems())) { throw new \\InvalidArgumentException('Order has no items'); } // 2. Guardar en la BD $db = new \\PDO('mysql:host=localhost;dbname=shop', 'user', 'pass'); $stmt = $db->prepare('INSERT INTO orders ...'); $stmt->execute([...]); // 3. Envío de email mail($order->getCustomerEmail(), 'Pedido confirmado', '...'); // 4. Registro en log file_put_contents('/var/log/orders.log', 'Order processed: '.$order->getId()); }}?>Aquí la clase OrderProcessor hace demasiado: valida, trabaja con la BD, envía email, registra en log. La violación de SRP lleva a que un cambio en la lógica de envío de email requiera modificar la clase responsable del procesamiento de pedidos.
Refactorización cumpliendo SRP
<?phpclass OrderValidator { public function validate(Order $order): void { if (empty($order->getItems())) { throw new \\InvalidArgumentException('Order has no items'); } }}
class OrderRepository { public function save(Order $order): void { // Lógica de guardado en la BD }}
class EmailNotifier { public function sendOrderConfirmation(Order $order): void { // Lógica de envío de email }}
class Logger { public function log(string $message): void { // Registro en log }}
class OrderProcessor { public function __construct( private OrderValidator $validator, private OrderRepository $repository, private EmailNotifier $notifier, private Logger $logger ) {} public function process(Order $order): void { $this->validator->validate($order); $this->repository->save($order); $this->notifier->sendOrderConfirmation($order); $this->logger->log('Order processed: '.$order->getId()); }}?>Ahora cada clase tiene una única responsabilidad. Un cambio en la lógica del email no afecta el trabajo con la BD.
2. Open-Closed Principle (OCP) — principio de abierto/cerrado
Teoría
Las entidades de software deben estar abiertas para extensión, pero cerradas para modificación. En otras palabras, debe poder agregar nueva funcionalidad sin cambiar el código existente.
Antipatrón
<?phpclass PaymentProcessor { public function process(string $type, float $amount): void { if ($type === 'credit_card') { // Procesamiento de tarjeta de crédito } elseif ($type === 'paypal') { // Procesamiento de PayPal\