Olhando para o polimorfismo em profundidade
Quando comecei esta série, falei sobre os quatro pilares da programação orientada a objetos. Cada um desses tópicos está listado e vinculado abaixo.
Neste ponto, eu normalmente gostaria de começar a passar para o próximo tópico. Antes de fazer isso, porém, gostaria de passar mais um post explorando o conceito de polimorfismo.
Em minha carreira, até agora, vi poucos tópicos que dão mais confusão e problemas aos que entram na programação orientada a objetos do que polimorfismo. Então, eu gostaria de discutir um pouco mais profundamente dentro do contexto da programação orientada a objetos e fora de qualquer framework ou aplicativo específico (como WordPress).
Neste post, farei uma rápida revisão do que discutimos até agora, depois voltarei ao polimorfismo.
Polimorfismo em profundidade
Em primeiro lugar, como mencionado, quero revisar rapidamente o que foi discutido até agora, especialmente se você encobriu qualquer um dos posts anteriores.
Não se preocupe: nada abaixo se transforma em código. Em vez disso, ele simplesmente define os termos que usamos para que você tenha uma ideia do que estou me referindo sempre que vir a palavra surgir ao longo desta série.
Abstração
Abstraímos a ideia de algo em uma classe. Em vez disso, vamos abstrair ideias em suas classes. E há uma ideia chave aqui: uma classe deve representar um substantivo.
Encapsulamento
Encapsulamento é realmente apenas uma palavra “grande" que se refere à ideia de gerenciar suas responsabilidades (ou acompanhar seus dados).
Herança
Herança refere-se à ideia de que uma classe, embora tenha sua própria implementação, literalmente herda propriedades, funções e implementação geral de uma classe pai.
Polimorfismo
O polimorfismo nos permite fazer referência a uma classe de um tipo quando ela pode ser declarada como outro tipo.
Com isso dito, é aqui que acho que as coisas podem ficar um pouco mais complicadas. Nas postagens anteriores, forneci vários exemplos de código diferentes (e peço que você os revise).
Mas no post de hoje, vou tentar explorar um pouco mais a ideia tanto na explicação quanto no código.
Relativo à herança
Se não for evidente neste ponto, o polimorfismo está altamente relacionado à herança. Pense desta forma: se uma classe herdar propriedades e métodos de outra classe, então ela pode “ficar no lugar” da classe pai.
Isso significa que se você tem algo como uma classe Content e duas subclasses, uma sendo uma Post e outra sendo uma Page, você pode instanciar a classe usando o tipo de referência Content.t
Mas em tempo de execução, será na verdade uma instância do tipo Post. Faz sentido? Aqui está algum código como exemplo.
Primeiro, vamos começar definindo uma classe Content :
<?php
class Content {
protected $title;
protected $content;
protected $metadata;
public function __construct()
{
$this->title = "Hello World!";
$this->content = "This is a sample piece of content.";
$this->metadata = "<This is the metadata of the post.>";
}
public function getTitle()
{
return $this->title;
}
public function getContent()
{
return $this->content;
}
public function getMetadata()
{
return $this->metadata;
}
}
Ele tem as propriedades gerais que você provavelmente espera – título, conteúdo e metadados. É verdade que essas propriedades são apenas strings, mas podem ser estruturas de dados mais elaboradas em uma situação do mundo real.
Agora vamos ver um Post :
<?php
class Post extends Content {
private $author;
public function __construct() {
parent::__construct();
$this->author = "Tom McFarlin";
}
public function getAuthor()
{
return $this->author;
}
}
O que acontece, então, se você chamar um método na classe Post, como getTitle, que não existe, mas existe na classe Content? Então, por causa da herança, ele procurará o método em Post, não o encontrará, então começará a procurá-lo em Content.
Se for encontrado, ele irá executá-lo.
Da mesma forma, podemos fazer algo assim com a classe Page e os dados de conteúdo. Primeiro, instanciamos a classe base e, em seguida, definimos propriedades específicas para a Page. Neste caso, será uma categoria.
<?php
class Page extends Content {
private $category;
public function __construct() {
parent::__construct();
$this->category = "Articles";
}
public function getCategory()
{
return $this->category;
}
}
Agora, quando executamos o código, podemos começar com o conteúdo:
<?php
$content = new Content();
echo $content->getTitle();
Observe que isso se parece com o que esperávamos, pois temos um título e conteúdo. Vejamos também o Post :
<?php
// These will work because they reside in the Content base class.
$post = new Post();
echo $post->getAuthor();
echo $post->getTitle();
Isso funciona porque temos um autor, mas também temos um título porque ele reside em Content. Mas se tentarmos chamar getAuthor em uma instância de Post?
<?php
// These will work because they reside in the Content base class.
$post = new Post();
echo $post->getAuthor();
echo $post->getTitle();
Vamos receber um erro porque o método não reside nessa classe.
Então o que devemos fazer? Como não temos tipos fortes em PHP, não podemos convertê-los em um tipo diferente.
Existem padrões de design para isso, que discutirei em um conjunto futuro de postagens, mas o PHP não permite isso tão facilmente quanto algumas outras linguagens (como C# ou Java).
Perguntas sobre polimorfismo
Felizmente, o código acima lhe dá uma ideia de como um tipo concreto como um Post ou uma Página pode ter implicitamente as propriedades e métodos de sua classe base, Content, usados em tempo de execução.
Mas também levanta algumas questões, não é? Por exemplo:
- Por que o polimorfismo é útil? Em última análise, é uma questão de flexibilidade. Ou seja, você pode escrever um tipo de conteúdo genérico, mas depois criar um Post ou uma Página como vimos acima. Isso nos dá todos os benefícios da classe Content e também a especificidade da classe Post, por exemplo.
- Isso parece ser mais confuso do que flexível. De certa forma, é confuso porque o código requer um pouco de rastreamento. Ou seja, você pode começar na classe Post e ter que procurar o que a classe Content oferece. Por outro lado, também torna muito fácil introduzir uma nova subclasse Content e usá-la quando for mais adequada em tempo de execução.
No que diz respeito a superclasses e subclasses, é aí que entra em jogo ter um IDE sólido.
É sempre bom ter um editor que você goste, claro, mas ter um que possa determinar intuitivamente qual é a classe pai, qual é a classe base, etc., pode ajudar muito a rastrear, depurar, seguir e escrever novos código.
Mas isso é conteúdo para outro post que virá depois que falarmos sobre padrões de design.

