PHP e o Princípio da Substituição de Liskov

Garantindo que instâncias de uma classe possam ser substituídas por instâncias de sub-classes sem quebrar o sistema.

Alan Willms
Aug 21, 2015 · 3 min read

Esse artigo continua a série sobre os cinco princípios do SOLID aplicados ao PHP. Agora veremos o terceiro deles, que é chamado de “Princípio da Substituição de Liskov”.

Esse conceito foi criado em 1974 por Barbara Liskov, que o definiu como:

Se para cada objeto O1 do tipo S existe um objeto O2 do tipo T de tal modo que para todos os programas P definidos em termos de T, o comportamento de P não muda quando O2 é substituído por O1, então S é um subtipo de T.

Essa definição é bastante técnica, mas Uncle Bob nos explica de uma forma mais simples:

Funções que usam ponteiros ou referências a classes-base devem ser capazes de usar objetos de classes derivadas sem o saber.

Ou seja, em qualquer lugar onde você usa uma instância de uma classe, você deve poder usar uma instância de uma sub-classe dela sem precisar alterar nada para que isso funcione:

Exemplos de Violações em PHP

Quando você estende o comportamento de outra classe ou implementa uma interface, um método pode quebrar o Princípio da Substituição de Liskov de diversas maneiras.

Vejamos alguns exemplos de violações:

Exigir que outro método seja chamado primeiro

A subclasse pode precisar que você informe alguma dependência ou faça alguma configuração antes que o método possa ser chamado com sucesso. Como o sistema espera que o objeto simplesmente funcione, ele não sabe que precisa configurar dependências antes de utilizá-lo.

Lançar uma exceção inesperada

Se o método na classe-mãe não lança uma exceção ou lança exceções somente de outros tipos, o código não saberá como tratá-la, e isso quebrará o sistema.

Sobrescrever um método com um corpo vazio

Essa é uma violação mais sutil, quando o método é sobrescrito, mas não faz nada. Se a subclasse não implementa o método, será que ela é mesmo uma especialização da classe-mãe?

Retornar um valor de tipo diferente da classe mãe

Todos os pontos em que o método é chamado no sistema, espera-se que ele retorne o mesmo tipo de dados. Se retornar um tipo inesperado, o sistema quebra.

Possíveis Soluções

Às vezes a primeira solução à qual recorremos é verificar qual é o tipo do objeto e prepará-lo ou tratá-lo de acordo:

No entanto, essa solução não é a ideal. Ao fazer isso, violamos o segundo conceito do SOLID, o Princípio do Aberto/Fechado, pois dessa forma precisaríamos alterar o código existente para introduzir um novo comportamento.

Como poderíamos resolver esse caso? Existem diversas maneiras, uma delas é fazer com que a classe receba as dependências no construtor e configure o que for necessário, desta forma o método log() sempre se comportará da maneira esperada:

Existe um pouco de polêmica quanto aos construtores violarem ou não o Princípio da Substituição de Liskov, mas perceba como essa solução é vantajosa ao utilizar um serviço de injeção de dependência.

Conclusão

Este princípio é um pouco mais complexo do que os dois primeiros, mas nos ajuda a evitar surpresas desagradáveis com polimorfismo.

Não existe uma solução “bala de prata” para todos os casos, pois muitas vezes é necessário mudar a forma de abstração do problema, e cada caso é diferente. No entanto, talvez essas duas sugestões possam ajudar a resolver o problema:

  • injetar as dependências e configurar no construtor ao invés de esperar que um setter ou um método seja chamado para preparar o objeto;
  • esperar interfaces ao invés de classes, assim você pode dividir melhor a sua hierarquia de classes e quem sabe implementar mais de uma interface para satisfazer todos os casos.

No próximo artigo veremos mais sobre isso, ao abordar o Princípio da Segregação de Interfaces.

Referências

* * *

P.S. Por que a foto dos patos? Em algumas linguagens não existem interfaces e você pode sobrescrever métodos com argumentos diferentes do original, então utiliza-se o conceito de duck typing. Veja essa piada.

Tableless

Um lugar para ler e discutir sobre desenvolvimento, design…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store