Design Patterns com PHP – Injeção de dependência

O Design pattern chamado injeção de dependência aplica o conceito de inversão de controle, isso é muito importante de você entender logo de início.Calma!Calma!Só coloquei isso no começo desse artigo porque é uma coisa que tenho que dizer quando quero explicar o conceito de injeção de dependência, e isso é muito, muito mais simples do que parece.

Pense no seguinte cenário, você tem uma classe de Checkout, e essa classe não sabe que tipo de gateway de pagamento vai usar, e para isso cria métodos para cada um deles, por exemplo:

class Checkout
{
    public function pagseguro()
    {
        // implementacao aqui
    }
    public function paypal()
    {
        // implementacao aqui
    }
    public function pagarme()
    {

       // implementacao aqui
    }
}

Já pensou ter que escrever a implementação de cada um desses gateways de pagamento em seus respectivos métodos?.Não seria errado(eu não gosto de apontar o dedo e falar que algo está definitivamente errado, é só uma maneira diferente de fazer), fazer isso, mas tem uma maneira muito mais amigável, que seria criar uma classe para cada tipo de pagamento e instanciar dentro de seus respectivos métodos na classe Checkout.

Ficando assim:

class Checkout
{
    public function pagseguro()
    {
        $checkout = new Pagseguro();
    }
    public function paypal()
    {
        $checkout = new PayPal();
    }
    public function pagarme()
    {
        $checkout = new PagarMe();
    }
}

Bem melhor certo?.Com certeza!Mas ainda tem espaço para melhorar, nesse exemplo eu posso diminuir o número de métodos para somente 1, ao invés desses 3, vou criar somente o método chamado payment, e vou passar por parâmetro(injetar a dependência) a instância que quero(o gateway escolhido).

E esse único método que criei tem um nome genérico(payment), assim pode ser usado por qualquer gateway de pagamento.

class Checkout
{
    public function pay($checkout)
    {
        $checkout->pay();
    }
}

Agora no cliente(que é onde instancio essa classe Checkout) eu faço o seguinte.

$checkout = new Checkout;
$checkout->payment(new Pagseguro);

Preste bem atenção agora, está vendo que dentro do método payment da classe Checkout estou chamando o método pay da injeção de dependência(intância da classe passada por parâmetro no método payment do checkout)?
O que aconteceria se a classe Pagseguro não tivesse o método pay?.E se eu passasse a instância da classe PayPal e ela não tivesse o método pay?.Está entendendo onde quero chegar?.Sim, nas interfaces.

As interfaces são contratos, que a classe que implementa ela, assina, com isso ela(classe) concorda que tem que ter os métodos criados dentro do contrato(interface), por exemplo.

interface CheckoutInterface
{
    public function payment();
}

class Pagseguro implements CheckoutInterface
{
    public function payment()
    {
        // implementação do pagamento do pagseguro
    }
}

class PayPal implements CheckoutInterface
{
    public function payment()
    {
        // implementação do pagamento do paypal
    }
}

Criando as classes de Pagamento implementando a interface CheckoutInterface me dá a certeza que a classe tem esse método payment, exigido para fazer o checkout dentro do método pay da classe Checkout.

Agora não interessa qual classe de Pagamento eu passe para o Checkout, eu sei que vai ter o método payment, justamente por ela ter um contrato assinado(a interface CheckoutInterface) que tem esse método, com isso a classe tem que ter esse método também.

Mas onde que entra essa tal inversão de controle?

Antes a instância da classe Pagseguro, PayPal e qualquer outro gateway, se dava dentro da classe, o controle de instanciar a classe de Pagamento estava dentro da classe Checkout, agora o controle foi invertido, essa instância se dá no cliente(onde instancio a classe Checkout) passando por parâmetro para o método pay(injeção de dependência).

Agora falta uma última coisa, no método pay da classe Checkout eu preciso ter a certeza que a instância que vou passar será de uma classe que tem um acordo com a interface CheckoutInterface.

class Checkout
{
    public function pay(CheckoutInterface $checkout)
    {
        $checkout->payment();
    }
}

$checkout = new Checkout();
$checkout->payment(new Pagseguro());
// ou
$checkout->payment(new PayPal());

Resumindo todo esse artigo: Injeção de dependência é um pattern onde passo a instância de uma classe para um método de outra classe, fazendo isso tiro o controle de criar a instância dentro dessa classe, passando agora essa responsabilidade para o cliente.

Pronto! Isso que é injeção de dependência e inversão de controle, simples demais, as vezes os nomes dão mais medo do que o código.


Se quiser conhecer meu trabalho mais a fundo, visite meu canal no YouTube e veja meus cursos completos clicando nos links abaixo.

🔥 Canal no YouTube: Ir para o canal no YouTube
🔥Veja meus cursos disponíveis: Ir para a lista de cursos

About the Author

Alexandre Eduardo Cardoso
Alexandre Eduardo Cardoso

Meu nome é Alexandre Cardoso e tenho 41 anos. Sou programador desde 2008, quando comecei a estudar e me especializar em PHP e Javascript. Já em 2011, dei minhas primeiras aulas de programação, e não consegui mais parar desde então. Ensinar é minha missão neste mundo!

1 Comment

Leave a comment

O seu endereço de email não será publicado. Campos obrigatórios marcados com *