> For the complete documentation index, see [llms.txt](https://senens-organization.gitbook.io/senenhermida.docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://senens-organization.gitbook.io/senenhermida.docs/solid.md).

# SOLID

Singleton se inventó lara tener una única instancia de un objeto no lara que fuera accesible desde todos los sitios

### 1. **Single Responsibility Principle (SRP)**

* **Definition**: A class should have one and only one reason to change, meaning that a class should have only one job.
* Ex: A class that calculates area of a shape also manages authentication, connection to db and rendering. WRONG!
* Problems of GOD class: dependencies, different logics, not decoupled
* Solution: Use layers, proper naming, DI

### 2. **Open/Closed Principle (OCP)**:

* **Definition**: Software entities (classes, modules, functions) should be open for extension but closed for modification
* How to accomplish
  * Avoid depending on specific implementations, making use of abstract classes or interfaces.
* Example in PHP:

```php
class LoginService
{
    public function login($user)
    {
        if ($user instanceof User) {
            $this->authenticateUser($user);
        } else if ($user instanceOf ThirdPartyUser) {
            $this->authenticateThirdPartyUser($user);
        }
    }
}
```

```php

class LoginService
{
    public function login(LoginInterface $loginService, UserInterface $user)
    {
        $loginService->authenticateUser($user);
    }
}

interface LoginInterface
{
    public function authenticateUser(UserInterface $user);
}

class UserAuthentication implements LoginInterface
{
    public function authenticateUser(UserInterface $user)
    {
        // TODO: Implement authenticateUser() method.
    }
}

class ThirdPartyUserAuthentication implements LoginInterface
{
    public function authenticateUser(UserInterface $user)
    {
        // TODO: Implement authenticateUser() method.
    }
}
```

### 3. **Liskov Substitution Principle (LSP)**:

* **Definition**: Objects of a derived class should be able to replace objects of the base class without affecting the correctness of the program.
* A subtype can either be a **class extending another class**, or a **class implementing an interface**.
* If we have a **`Tesla`** is a subtype of a **`Car`**, then I should be able to **`drive`** either a **`Car`** or a **`Tesla`** the same way.
* Classes extensions must use the same prototype (method signatures) as their parents. When implementing an Interface there is a contract in the input but should be a contract on the output to. (Also exceptions)
  * You can widen the types of method arguments in child classes and interface implementations, but not make them more narrow.
  * You can make the return types in child classes and interface implementations more narrow, but not widen them.
  * In subtypes, you should try to avoid throwing exceptions that are not thrown by the parent class or documented on the interface being implemented (where possible).
  * You should consider closing off your constructor method arguments from modification in subtypes by making `final`
* Example in PHP:

```php
class Bird {
    public function fly() {
        // Logic for flying
    }
}

class OstrichAvestruz extends Bird {
    public function fly() {
        // Ostrich can't fly, so this method does nothing
			throw \\Exception();
    }
}

function makeBirdFly(Bird $bird) {
    $bird->fly();
}

$ostrich = new OstrichAvestruz();
makeBirdFly($ostrich); // This should not lead to unexpected behavior
```

<https://madewithlove.com/blog/liskov-substitution-principle-explained/#:~:text=Applying> the Liskov Substitution Principle,narrow%2C but not widen them.

### 4. **Interface Segregation Principle (ISP)**

* **Definition**: A client should never be forced to implement an interface that it doesn’t use
* Many client-specific interfaces are better than one general-purpose interface
* Solution:
  * Use dependencies
  * Split the class into => interfaces + abstractions
  * Implement abstractions in a way that don’t knoe about other classses’ behavior

```php
interface WorkerInterface {
	public function work(); 
	public function sleep();
}
class Worker implements WorkerInterface { 
	public function work(){} 
	public function sleep(){}
}
class Android implements WorkerInterface {
	public function work(){} 
	public function sleep(){ return null; }
}
class Captain {
	 public function manage (WorkerInterface $worker) {
		$worker->work();
		$worker->sleep();
	}
}
```

\=>

```php
interface WorkableInterface {
	public function work(); 
}
interface SleepableInterface {
	public function sleep();
}
class Worker implements WorkableInterface, SleepableInterface{ 
	public function work(){} 
	public function sleep(){}
}
class Android implements WorkableInterface {
	public function work(){} 
}
class Captain {
	 public function manage (¿?¿?¿? $worker) {
		$worker->work();
		$worker->sleep();
	}
}
```

\=>

```php
interface ManageableInterface {
	public function beManaged(); 
}
interface WorkableInterface {
	public function work(); 
}
interface SleepableInterface {
	public function sleep();
}
class Worker implements WorkableInterface, SleepableInterface, ManageableInterface{ 
	public function work(){} 
	public function sleep(){}
	public function beManaged(){
		$this->work();
		$this->sleep(); 
	}	
}
class Android implements WorkableInterface, ManageableInterface {
	public function work(){} 
	public function beManaged(){
		$this->work();
	}
}
class Captain {
	 public function manage (ManageableInterface $worker) {
		$worker->beManaged();
	}
}
```

### 5. **Dependency Inversion Principle (DIP)**

* Definition: high-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details, details houls depend on abstractions
* It encourages the use of interfaces or abstract classes to decouple components.

```php
class PasswordReminder {
    private $dbConnection;

    public function __construct(MySQLConnection $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}
```

```php
interface DBConnectionInterface {
    public function connect();
}
class MySQLConnection implements DBConnectionInterface {
    public function connect() {
        return "Database connection";
    }
}

class PasswordReminder {
    private $dbConnection;

    public function __construct(DBConnectionInterface $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}

High-level modules typically have higher-level responsibilities and are responsible for coordinating or managing various lower-level components or modules.
Low-level modules usually have lower-level responsibilities and handle specific, fine-grained tasks or operations.
```

PasswordReminder => hig level

MySQLConnection => low level

```php
class Lamp {
    //TRUE = on, FALSE = Off
    protected bool $currentState = FALSE;

    public function turnOn() {
        $this->currentState = TRUE;
    }

    public function turnOff() {
        $this->currentState = FALSE;
    }

    public function getState() {
        return $this->currentState;
    }

    public function getStateString(): string {
        if ($this->currentState) {
            return 'On';
        } else {
            return 'Off';
        }
    }
}

class Button {
    protected Lamp $lamp;

    public function __construct(Lamp $l) {
        $this->lamp = $l;
    }

    public function On() {
        $this->lamp->turnOn();
    }

    public function Off() {
        $this->lamp->turnOff();
    }
}

$l = new Lamp();
$b = new Button($l);
echo $l->getStateString(); //Off

$b->On();
echo $l->getStateString(); //On

```

```php
interface DeviceInterface {
    public function turnOn();
    public function turnOff();
}

class Lamp implements DeviceInterface {
		// same
}

interface ButtonInterface {
    public function On();
    public function Off();
}

class Button implements ButtonInterface {
    protected DeviceInterface $di;

    public function __construct(DeviceInterface $di) {
        $this->di = $di;
    }

    public function On() {
        $this->di->turnOn();
    }

    public function Off() {
        $this->di->turnOff();
    }
}

$l = new Lamp();
$b = new Button($l);
echo $l->getStateString(); //Off

$b->On();
echo $l->getStateString(); //On
```

"Abstractions should not depend on details, details should depend on abstractions."

```php
interface DataProvider {
  public function getData(); 
}

class MySQLDataProvider implements DataProvider {
  
  private $db;
  
  public function __construct() {
    $this->db = new MySQLDB();
  }

  public function getData() {
    return $this->db->query("SELECT..."); 
  }
}
```
