Parte 2 – WordPress e Programação Orientada a Objetos: Um Exemplo do Mundo Real

Publicados: 2021-07-29

Em nossa Visão geral do WordPress e da programação orientada a objetos, analisamos a teoria por trás da programação orientada a objetos (OOP) e o que esperar ao usá-la.

Antes de prosseguirmos com exemplos de codificação mais específicos usando OOP, neste artigo tentaremos explicar como um cenário do mundo real pode ser abordado com a mentalidade diferente necessária para OOP e como isso é analisado usando objetos e classes.

Um cenário da vida real: enviando um SMS

Isso é mais como um cenário de vida “passada”, na verdade, já que o SMS é cada vez menos usado hoje em dia, mas como você verá, há uma razão para usarmos isso como exemplo!

Suponha que você tenha um dispositivo móvel e queira enviar uma mensagem de texto para um de seus contatos. Mantendo o exemplo o mais simples possível, a sequência de ações seria:

  1. Preparar a mensagem
  2. Selecione um de seus contatos e adicione como destinatário
  3. Envie a mensagem

Então vamos tentar visualizar os passos que você seguiria para enviar sua mensagem:

Adicionamos algumas descrições mais detalhadas das ações, mas mais ou menos tudo o que você faz são 3 etapas básicas. Você prepara a mensagem no editor do dispositivo, seleciona o destinatário de seus contatos e envia a mensagem. E você está feito! Sua mensagem já foi enviada.

Agora, se formos representar em código uma aplicação que envia uma mensagem SMS devemos analisar qual rota é melhor seguir; a abordagem processual ou OOP.

A Aplicação com uma Abordagem Processual

Se você é um desenvolvedor de plugins do WordPress, provavelmente está familiarizado com programação procedural .

Como descrevemos anteriormente, a programação procedural é um tipo de programação imperativa, onde nossos programas consistem em um ou mais procedimentos. Então, como desenvolvedor, você divide seu plugin em um monte de variáveis ​​que armazenam seus dados e funções que operam nos dados.

Em nosso exemplo acima com a mensagem SMS, você realizaria uma série de ações que levariam ao resultado desejado. Como você já deve ter adivinhado, você teria, por exemplo, uma variável que contém o conteúdo de texto da mensagem, uma função com um parâmetro $contact que retorna o número do telefone e, por fim, uma função que envia a mensagem. No código ficaria assim:

 function get_phone_number( $contact ) { // Code that finds the contact's number in the list of contacts return $phone_number; } function send_sms( $contact, $message ) { $phone_number = get_phone_number( $contact ); // Code that sends the message to this number print "Message Sent!"; }

E você usaria assim:

 $text = "Hello John"; function send_message( "John Doe", $text );

Assim, você concluiria uma série de tarefas que o levariam ao resultado desejado.

Neste exemplo muito simples, claro, que tem requisitos limitados e muito específicos, não há razão para considerar o uso de POO. A programação procedural é mais do que suficiente para atingir seu objetivo. Mas, se você pensar em alguns cenários sobre como esse aplicativo pode se expandir no futuro, poderá perceber que, a longo prazo, poderá ter problemas em termos de escalabilidade. Vamos tentar explicar o porquê abaixo.

Expandindo o Aplicativo com Abordagem Processual

Digamos que você queira melhorar este aplicativo e fornecer a capacidade de enviar outros tipos de mensagens, como um e-mail, por exemplo. A função que entrega a mensagem seria diferente em cada caso.

Ao enviar um e-mail, você precisa do endereço de e-mail do contato, não do número de telefone. Além disso, precisaremos adicionar um parâmetro na função final send_message() que corresponderá ao tipo de tecnologia que usamos; e-mail ou SMS.

O código correspondente pode ser algo assim:

 function get_phone_number( $contact ) { // Code that finds the contact's number return $phone_number; } function get_email_address( $contact ) { // Code that finds the contact's email address return $email_address; } function send_sms( $contact, $message ) { $phone_number = get_phone_number( $contact ); // Code that sends the message to this number print "SMS Sent!"; } function send_email( $contact, $message ) { $email_address = get_email_address( $contact ); // Code that sends the email to this number print "Email Sent!"; } function send_message( $contact, $message, $technology ) { if ( $technology == "SMS") { send_sms( $phone_number, $message ); } else if ( $technology == "Email") { send_email( $email_address, $message ); } }

Então, não é como se isso não pudesse ser implementado com uma abordagem processual. Mas se você é um desenvolvedor experiente, provavelmente já entendeu como isso pode se tornar confuso no futuro.

As desvantagens de uma abordagem processual

E se tivéssemos vários tipos de mensagens? As instruções if se tornariam irritantemente grandes. E, mais importante, e se você tivesse funções que usam a função send_message() ? Nesse caso, você precisaria adicionar o parâmetro $technology em todas essas funções também.

À medida que seu código cresce, as funções estarão em todo lugar, o que significa que você começará a copiar/colar pedaços de código (nunca desejável), e fazer uma pequena alteração em uma função pode quebrar várias outras funções. Todos nós já estivemos lá. Você gostaria de evitar isso e ser capaz de adicionar facilmente recursos ao seu código sem interferir muito na estrutura.

Hospede seu site com a Pressidium

GARANTIA DE DEVOLUÇÃO DO DINHEIRO DE 60 DIAS

VEJA NOSSOS PLANOS

A programação orientada a objetos (ou OOP) é ​​um paradigma de programação que tenta resolver esse problema, permitindo-nos estruturar nosso plugin em pequenos pedaços de código reutilizáveis, chamados classes . Conforme descrevemos em nosso artigo OOP Overview, uma classe é basicamente um modelo que usamos para criar instâncias individuais da classe, chamadas objects .

Um objeto contém dados e código. Ainda temos variáveis ​​que podem armazenar informações, chamadas de propriedades . E procedimentos que operam nos dados, chamados métodos .

A aplicação com uma abordagem OOP

Agora vamos analisar o mesmo cenário acima com uma abordagem OOP.

Primeiro, vamos definir quais objetos temos aqui, quais características cada um possui e quais ações eles realizam. As características são o que mais tarde serão nossas propriedades e ações serão nossas funções ou métodos como são chamados em OOP.

Vamos pensar no que temos no primeiro cenário de enviar um SMS da forma mais simples possível. Existe um dispositivo que possui uma interface que usamos para enviar a mensagem SMS. Temos o conteúdo da mensagem, escolhemos um contato como destinatário e por fim a mensagem.

 <?php /** * Plugin Name: Send Message */ interface MessagingCapable { public function send_message( $contact, $message ); } class Phone implements MessagingCapable { public function send_message( $contact, $message ) { print "You sent" . $message ; } } function say_hi( MessagingCapable $device, $contact, $message ) { $device->send_message( $contact, $message ); }

Declaramos a classe Phone que implementa a interface MessagingCapable . Então temos que implementar todos os métodos declarados nele. A função say_hi() requer 3 parâmetros:

  1. Um dispositivo que suporte mensagens
  2. Um contato
  3. A mensagem

Para realmente enviar uma mensagem, usamos esta função assim:

 $phone = new Phone(); say_hi( $phone, "John Doe", "Hello John" );

Estamos basicamente criando um objeto instanciando a classe Phone e passando o conteúdo do contato e da mensagem. Isso geraria:

 You sent "Hello John"

Demonstramos este cenário simples de enviar uma mensagem de texto usando classes. Na próxima seção, veremos como podemos expandir os recursos do aplicativo seguindo a abordagem OOP e, durante a ampliação, examinaremos onde os recursos OOP desempenham seu papel, bem como os benefícios do uso dessa técnica.

Expandindo o aplicativo com a abordagem OOP

Vamos adicionar a capacidade de enviar e-mails também, como fizemos antes de forma processual.

Independentemente do dispositivo, idealmente gostaríamos de usar a função say_hi() da mesma maneira. Dê uma olhada no código abaixo:

 <?php /** * Plugin Name: Send Message */ interface MessagingCapable { public function send_message( $contact, $message ); } class Phone implements MessagingCapable { public function send_message( $contact, $message ) { print ('You sent a "' . $message . '" SMS to ' . $contact ); } } class Computer implements MessagingCapable { public function send_message( $contact, $message ) { print ('You sent a "' . $message . '" email to ' . $contact ); } } function say_hi( MessagingCapable $device, $contact, $message ) { $device->send_message( $contact, $message ); }

Quando usamos esse pedaço de código, pegamos o dispositivo móvel para enviar um SMS e o computador para enviar um e-mail. Nós ou iríamos:

 say_hi ( new Phone(), "John Doe", "Hello John" );

ou:

 say_hi ( new Computer(), "John Doe", "Hello John" );

isso resultaria em You sent a "Hello John" SMS to John Doe e You sent a "Hello John" email to John Doe correspondentemente.

Aqui já começamos a detectar alguns recursos de POO. Introduzimos interfaces usando a interface MessagingCapable .

Uma interface declara um conjunto de métodos que devem ser implementados pela classe sem definir como esses métodos são implementados. Todos os métodos declarados em uma interface devem ser públicos.

O PHP não suporta herança múltipla, o que significa que uma classe não pode herdar as propriedades/métodos de várias classes pai.

Embora possa estender apenas uma classe, pode implementar várias interfaces.

Usar um telefone para enviar uma mensagem será diferente de usar um computador. Instâncias de classes diferentes agem de forma diferente quando solicitadas a realizar a mesma ação (ou seja, send_message() ). Este é um exemplo de polimorfismo. Se posteriormente criarmos um novo dispositivo, não precisaremos modificar nosso código para acomodá-lo, desde que todos compartilhem a mesma interface.

Também gostaríamos de salientar aqui que já vemos a diferença na legibilidade também. A maneira como finalmente usamos esse script apenas codificando:

 say_hi( new Computer(), "John", "Hi" );

Isso é totalmente direto para qualquer desenvolvedor que trabalha no projeto. E, claro, quanto mais complexo o plugin, fica mais óbvio o quão útil isso é, especialmente quando se trabalha em equipe.

Para tentar explicar melhor como é fácil expandir seu plugin em Programação Orientada a Objetos, vamos tentar adicionar mais algumas funcionalidades.

Adicionando mais funcionalidades

Se quisermos adicionar a capacidade de navegar na internet, basta adicionar uma interface extra para qualquer dispositivo que possa responder a essa capacidade, como um computador, por exemplo.

 interface InternetBrowsingCapable { public function visit_website( $url ); }

A implementação desta interface será codificada assim:

 class Computer implements MessagingCapable, InternetBrowsingCapable { public function send_message( $contact, $message ) { print ('You sent a "' . $message . '" email to ' . $contact ); } public function visit_website( $url ) { print ('You visited "' . $url ); } }

Então na classe Computer atual nós apenas adicionamos a interface extra a ser implementada, já que um computador pode enviar uma mensagem e navegar na internet, e o visit_website( $url ) .

NOTA: Claro, como visitar uma url é totalmente irrelevante com a função say_hi() , também introduziremos uma nova função, algo como:

 function visit_url( InternetBrowsingCapable $device, $url ) { $device->visit_website( $url ); }

E é isso! Para qualquer dispositivo que possa visitar uma URL, podemos usar esta função como fizemos com o computador. Não há preocupações de que você quebrará o restante da funcionalidade. Isso mostra a escalabilidade disponível ao usar OOP em comparação com a programação procedural.

Vamos adicionar um dispositivo smartphone apenas para demonstrar mais alguns recursos. Aqui está todo o código, com a adição da classe smartphone para que você possa ter uma ideia melhor do que está acontecendo:

 <?php /* * Plugin Name: Communication Plugin */ interface MessagingCapable { public function send_message( $contact, $message ); } interface InternetBrowsingCapable { public function visit_website( $url ); } class Phone implements MessagingCapable { public function send_message( $contact, $message ) { print 'You sent a "' . $message . '" SMS to ' . $contact; } } class Computer implements MessagingCapable, InternetBrowsingCapable { public function send_message( $contact, $message ) { print 'You sent a "' . $message . '" email to ' . $contact; } public function visit_website( $url ) { print 'You visited "' . $url; } } class Smartphone extends Phone implements InternetBrowsingCapable { public function visit_website( $url ) { print 'You visited "' . $url; } public function send_message( $contact, $message ) { parent::send_message( $contact, $message ); print ' from your smartphone'; } } function say_hi( MessagingCapable $device, $contact, $message ) { $device->send_message( $contact, $message ); } function visit_url( InternetBrowsingCapable $device, $url ) { $device->visit_website( $url ); }

A classe Smartphone estende a classe pai Phone e implementa a interface InternetBrowsingCapable . Isso significa que ele pode enviar uma mensagem e visitar um URL. Aqui, detectamos o recurso de herança. Em outras palavras, temos uma hierarquia de classes, uma classe pai(Telefone) e uma subclasse(Smartphone).

Assim, um objeto Smartphone herda todas as propriedades e comportamentos da classe Phone pai. Dessa forma, dentro da classe filha podemos adicionar um método ou sobrescrever um método da classe pai, como fizemos com o send_message() na classe Smartphone. Fizemos isso para alterar a saída. Poderíamos ignorar totalmente este método e usar o send_message() da classe pai como está.

Você pode experimentar o código colando-o no bloco de código nesta ótima ferramenta online PHP. Sob o código, tente qualquer uma dessas linhas de código e veja os diferentes resultados.

 say_hi ( new Phone(), "John Doe", "Hello John" ); say_hi ( new Computer(), "John Doe", "Hello John" ); say_hi ( new Smartphone(), "John Doe", "Hello John" ); visit_url ( new Smartphone(), "https://www.pressidium.com" ); visit_url ( new Computer(), "https://www.pressidium.com" );

Para uma compreensão ainda melhor de todo o conceito, dê uma olhada no diagrama de classes do código acima.

Conforme descrito acima, ao projetar os relacionamentos entre as classes, não incluímos os elementos comuns na classe filha. Além disso, não se esqueça de prestar atenção no guia à esquerda para identificar as relações e a visibilidade de suas propriedades e métodos.

Se você também quiser ver o recurso Encapsulation em ação, tente incluir uma classe Contact em qualquer um dos scripts de exemplo acima que fornecemos. A classe ficaria assim:

 class Contact { private $name; private $phone_number; private $email_address; public function __construct( $name, $phone_number, $email_address ) { $this->name = $name; $this->phone_number = $phone_number; $this->email_address = $email_address; } public function get_name() { return $this->name; } public function get_phone_number() { return $this->phone_number; } public function get_email_address() { return $this->email_address; } }

O método __construct() , por design, é chamado automaticamente na criação de um objeto. Agora, quando instanciamos a classe Contact, seu construtor é chamado e define os valores de suas propriedades privadas. Então usamos nossos “getters” que são os métodos públicos get_name() , get_phone_number() e get_email_address() para recuperar esses valores.

O encapsulamento está agrupando os dados com os métodos que operam nos dados enquanto restringe o acesso direto, evitando a exposição de detalhes de implementação ocultos.

Conclusão

Espero que este artigo tenha ajudado você a entender a programação orientada a objetos de uma maneira mais prática. OOP realmente ajuda a facilitar a expansão do aplicativo no futuro, se necessário, por ser claro e reutilizável.

Além disso, um plugin que usa OOP será mais rápido e fácil de executar. Isso porque os métodos comuns a todos os objetos de uma classe consomem memória apenas uma vez, durante sua declaração.

A segurança também é melhorada devido ao encapsulamento. Na programação procedural, por outro lado, todos os dados são globais, o que significa que o acesso está disponível de qualquer lugar.

Como resultado do exposto, a manutenção do código, a produtividade, a escalabilidade e a solução de problemas também se tornam muito mais fáceis para você e sua equipe.

Nos próximos artigos desta série veremos este estilo de programação em ação aplicando-o a um plugin WordPress. Especificamente, criaremos uma cópia do plug-in Limit Login Attempts versão 1.7.1 criado por Johan Eenfeldt, mas convertido o máximo possível com uma abordagem Orientada a Objetos.

Durante esse processo, dividiremos o fluxo do plug-in e definiremos os requisitos. Daqui para frente, testaremos nossos primeiros pensamentos sobre o design do plug-in e, na etapa de implementação, escreveremos o código. Durante o processo de implementação faremos alguns retrocessos e redesenhos, se necessário, para obter os resultados desejados.

No entanto, não entraremos em detalhes sobre todas as partes do código. Em vez disso, gostaríamos de nos concentrar em compartilhar a maneira como os plugins são construídos de maneira orientada a objetos. Estamos confiantes de que, uma vez que você terminar de ler esta série de artigos, você pode muito bem criar seu próprio plugin OOP.

Clique aqui para ler a Parte 3 em nossa Série de Programação Orientada a Objetos

Veja também

  • WordPress e programação orientada a objetos – uma visão geral