Princípios SOLID: o que são e como aplicá-los no PHP/Laravel (Parte 05 - Inversão de Dependência)
Tags: php, solid, architecture, laravel
Published: 2021-03-17 22:17:07

Dando continuidade à série de artigos sobre princípios SOLID, trago hoje o quinto e último dos princípios.

# Dependency Inversion Principle
_(Princípio da Inversão de Dependência)_
> Entidades devem depender de abstrações e não de algo concreto. Isso significa que módulos de alto nível não podem depender de módulos de baixo nível, e sim de abstrações.

Como eu citei na parte 04 "abstração é o coração da orientação a objetos. Em PHP, nós conseguimos alcançar um nível de abstração utilizando interfaces e classes abstratas". Ou seja, assim como na parte 04 nós vamos aplicar o nosso exemplo de `Employees` e `Contractor` usando interfaces.

Quando trabalhamos com arquitetura em camadas (que no nosso caso é as camadas *Controller*, *Service*, *Repository* e *Model*) o ideal é que possamos seguir o fluxo da requisição a partir do *Controller*, e que as camadas mais externas não saibam nada do que acontece nas camadas mais internas.

Por exemplo:

O *Controller* não pode depender diretamente do *Service*, assim como o *Service* não pode depender da camada de *Repository*.

Mas por quê?

Pois dessa forma essas camadas estariam dependendo de implementações concretas. Ou seja, se eu mudar alguma coisa no meu *Service*, pode impactar diretamente no *Controller* e acabar "quebrando" a aplicação. Isso aumenta o acoplamento entre as classes, o que é uma má prática.

E como resolver isso?

Com a inversão de dependência!

Na parte 04, criei 2 interfaces com o objetivo de deixá-las segregadas, cada uma com suas particularidades.

```php
interface UserInterface
{
  public function register(array $attributes, UserRepository $userRepository);
}

interface ContractorInterface
{
  public function calcWorkedHours(array $hours);
}
```

Para poder fazer a inversão de dependência, eu preciso injetar a interface do *Service* no *Controller*. Mas como fazer isso se temos duas interfaces?

A resposta é simples: herança!

Eu vou criar uma interface, e as duas interfaces criadas anteriormente (`UserInterface` e `ContractorInterface`) irão estendê-la.

```php
interface ServiceInterface
{
}

interface UserInterface extends ServiceInterface
{
  public function register(array $attributes, UserRepository $userRepository);
}

interface ContractorInterface extends ServiceInterface
{
  public function calcWorkedHours(array $hours);
}
```

Dessa forma, conseguimos concentrar toda essa camada de abstração em um único ponto.

Agora, vamos ao *Controller* e vamos injetar essa interface.

```php
class UserRegistrationController extends Controller
{
    protected $userService;

    public function __construct(ServiceInterface $userService)
    {
        $this->userService = $userService;
    }

    // implementação do código
}
```

Percebam que mesmo o nosso atributo seja nomeado como `$userService`, ele é do tipo `ServiceInterface`. E dessa forma evitamos um forte acoplamento entre as camadas concretas, deixando todo serviço a cargo da abstração, que no nosso caso é a `ServiceInterface`.

Fica aqui o desafio: tente fazer o mesmo processo entre as camadas de *Service* e *Repository*. :)

Espero que tenham gostado dessa série de artigos sobre SOLID, e em breve trarei novos conteúdos.

Fui!