Algunos de estos principios son tratados en el curso de arquitectura hexagonal en Laravel.
En ingeniería de software, SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion) es un acrónimo mnemónico introducido por Robert C. Martin (Uncle Bob) a comienzos de la década del 2000 que representa cinco principios básicos de la programación orientada a objetos y el diseño.
Cuando estos principios se aplican en conjunto es más probable que un desarrollador cree un sistema que sea fácil de mantener y ampliar con el tiempo.
Los principios SOLID son guías que pueden ser aplicadas en el desarrollo de software para eliminar malos diseños provocando que el programador tenga que refactorizar el código fuente hasta que sea legible y extensible. Puede ser utilizado con el desarrollo guiado por pruebas, y forma parte de la estrategia global del desarrollo ágil de software y desarrollo adaptativo de software.
S: SRP
Principio de responsabilidad única (Single responsibility principle) La noción de que un objeto solo debería tener una única razón para cambiar.
La S de SOLID puede ser el principio más sencillo de entender. Queremos que en este caso una clase sólo haga una cosa, para ello, podemos tener el ejemplo de un controlador que únicamente tiene un método __invoke y se encarga de listar artículos. Con muy pocas línea de código y con únicamente una responsabilidad (listar artículos) cumplimos con este principio.
<?php
namespace Core\BoundedContext\Course\Infrastructure\Controllers;
use App\Http\Controllers\Controller;
use Core\BoundedContext\Course\Application\Actions\ListCourses;
use Core\BoundedContext\Course\Infrastructure\Persistence\Eloquent\CourseRepository;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
final class ListCoursesGetController extends Controller
{
public function __construct(private CourseRepository $repository) {}
public function __invoke(): JsonResponse {
$coursesResponse = (new ListCourses($this->repository))();
return new JsonResponse(
[
'courses' => $coursesResponse->toArray()
],
Response::HTTP_OK,
);
}
}O: OCP
Principio de abierto/cerrado (Open/closed principle)
La noción de que las "entidades de software deben estar abiertas para su extensión, pero cerradas para su modificación".
La O de SOLID es muy simple, imagina que tienes un proceso de registro en tu plataforma que inicialmente funciona con correo electrónico. Pasado un tiempo te piden añadir Facebook, después Twitter y después Gmail. Al final, si no lo hacemos bien, podemos tener un lío importante a nivel de código.
La forma de solucionar esto es con el siguiente ejemplo, donde inicialmente trabajamos únicamente con correo electrónico, pero si algún día queremos añadir Facebook, sólo deberemos seguir el mismo proceso reutilizando parte de la lógica a través de un nuevo servicio.
Register.php
<?php
namespace App\Contracts;
use Illuminate\Http\Request;
interface Register {
public function register(Request $request);
}RegisterRepository.php
<?php
namespace App\Repositories;
use App\Contracts\Register as RegisterContract;
use Illuminate\Http\Request;
class RegisterRepository {
public function __construct(private RegisterContract $registerContract) {}
public function register(Request $request) {
$this->registerContract->register($request);
}
}RegisterWithEmail.php
<?php
namespace App\Services;
use App\Contracts\Register as RegisterContract;
use App\Models\User;
use Illuminate\Http\Request;
class RegisterWithEmail implements RegisterContract
{
public function register(Request $request)
{
$user = User::create([
// ...
]);
return $user;
}
}RegisterWithEmailController.php
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Services\RegisterWithEmail;
use App\Repositories\RegisterRepository;
use Illuminate\Http\Request;
class RegisterWithEmailController extends Controller
{
public function __construct(private RegisterWithEmail $registerWithEmail) {}
public function __invoke(Request $request)
{
$registerRepository = new RegisterRepository($this->registerWithEmail);
$registerRepository->register($request);
// perform operations
}
}L: LSP
Principio de sustitución de Liskov (Liskov substitution principle)
La noción de que los "objetos de un programa deberían ser reemplazables por instancias de sus subtipos sin alterar el correcto funcionamiento del programa".
La L de SOLID es quizá la más compleja de entender, aunque es realmente sencilla. Este principio SOLID dice que cualquiera de las subclases de una clase deben poder reemplazar a su clase padre sin alterar su comportamiento.
Algunas de las reglas a seguir para aplicar este principio son las siguientes:
El número de parámetros de entrada en el método de las subclases debe ser igual o mayor que el número de parámetros de entrada del método principal en la clase padre.
El tipo de los parámetros de las subclases deben ser del mismo tipo o equivalente que los de la clase padre.
Los tipos de los valores devueltos del método de las subclases deben ser iguales o más específicos que los tipos devueltos por el mismo método en la clase padre.
Las pre-condiciones para cualquier método en las subclases no pueden ser más que las de la clase padre.
Las post-condiciones de las clases hijas deben ser al menos o iguales a las de la padre.
Los tipos de excepciones de las subclases deben ser del mismo tipo o más específico que el de la clase padre.
DatabaseUnitRepository.php
<?php
class DatabaseUnitRepository implements UnitRepository {
public function all(): array {
return Unit::all()->toArray();
}
}FilesystemUnitRepository.php
<?php
class FilesystemUnitRepository implements UnitRepository {
public function all(): array {
return File::allFiles(storage_path("units"));
}
}UnitRepositoryInterface.php
<?php
interface UnitRepository {
public function all(): array;
}I: ISP
Principio de segregación de la interfaz (Interface segregation principle)
La noción de que "muchas interfaces cliente específicas son mejores que una interfaz de propósito general".
La I de SOLID es muy simple. Este principio SOLID dice es mejor tener muchas interfaces en lugar de una única interfaz que lance excepciones cuando no se pueda implementar. Cabe decir que no debemos crear interfaces en exceso, siempre hay que tratar de ser coherentes para que nuestro trabajo se simplifique al máximo sin caer en el exceso.
Primero vamos a ver un ejemplo donde se viola el principio de segregación de interfaz.
Employee.php
<?php
interface Employee {
public function work(): void;
public function eat(): void;
public function drinkCoffee(): void;
}Person.php
<?php
class Person implements Employee {
public function work(): void {
// TODO employee can work
}
public function eat(): void {
// TODO employee can eat
}
public function drinkCoffee(): void {
// TODO employee can drink a coffee
}
}Robot.php
<?php
class Robot implements Employee {
public function work(): void {
// TODO robot can work
}
public function eat(): void {
throw new Exception("Robot don't eat!");
}
public function drinkCoffee(): void {
throw new Exception("Robots don't drink coffee!");
}
}A continuación, veamos cómo quedaría un caso cumpliendo el principio de segregación de interfaz.
Employee.php
<?php
interface EmployeeWork {
public function work(): void;
}EmployeeDrinkCoffee.php
<?php
interface EmployeeDrinkCoffee {
public function drinkCoffee(): void;
}EmployeeEat.php
<?php
interface EmployeeEat {
public function eat(): void;
}Person.php
<?php
class Person implements EmployeeWork, EmployeeEat, EmployeeDrinkCoffee {
public function work(): void {
// TODO employee can work
}
public function eat(): void {
// TODO employee can eat
}
public function drinkCoffee(): void {
// TODO employee can drink a coffee
}
}Robot.php
<?php
class Robot implements EmployeeWork {
public function work(): void {
// TODO employee can work
}
}D: DIP
Principio de inversión de dependencia (Dependency inversion principle)
La noción de que se debe "depender de abstracciones, no depender de implementaciones".
Siguiendo el ejemplo utilizado en el curso, nosotros tenemos una interfaz para gestionar el repositorio de cursos en lugar de la clase concreta.
CourseRepository.php
<?php
namespace Core\BoundedContext\Course\Domain;
interface CourseRepository {
public function list(): Courses;
public function save(Course $course): void;
public function find(CourseId $id): ?Course;
public function delete(CourseId $id): void;
}EloquentCourseRepository.php
<?php
namespace Core\BoundedContext\Course\Infrastructure\Persistence\Eloquent;
final class EloquentCourseRepository implements CourseRepositoryContract {
public function __construct(private CourseModel $model) {}
public function find(CourseId $id): ?Course {
// find and return a course
}
public function list(): Courses {
// return a list of courses
}
public function save(Course $course): void {
// save course
}
public function delete(CourseId $id): void {
// delete course
}
}ListCoursesGetController.php
<?php
namespace Core\BoundedContext\Course\Application\Actions;
use Core\BoundedContext\Course\Application\Responses\CoursesResponse;
use Core\BoundedContext\Course\Domain\CourseRepository;
class ListCourses {
public function __construct(private CourseRepository $repository) {}
public function __invoke(): CoursesResponse {
$courses = $this->repository->list();
return CoursesResponse::fromCourses($courses);
}
}
Curso Laravel 12
Completo 2026
El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.
star Incluido en cualquier suscripción