Melhorando o código do WordPress com PHP moderno
Publicados: 2022-03-10O WordPress nasceu há quinze anos e, como historicamente preservou a compatibilidade com versões anteriores, as versões mais recentes de seu código não puderam fazer uso total dos recursos mais recentes oferecidos pelas versões mais recentes do PHP. Embora a versão mais recente do PHP seja 7.3.2, o WordPress ainda oferece suporte até PHP 5.2.4.
Mas esses dias acabarão em breve! O WordPress atualizará seu suporte mínimo à versão PHP, passando para PHP 5.6 em abril de 2019 e PHP 7 em dezembro de 2019 (se tudo correr conforme o planejado). Podemos então finalmente começar a usar os recursos de programação imperativa do PHP sem medo de quebrar os sites de nossos clientes. Viva!
Como os quinze anos de código funcional do WordPress influenciaram a forma como os desenvolvedores construíram com o WordPress, nossos sites, temas e plugins podem estar repletos de códigos abaixo do ideal que podem receber uma atualização com prazer.
Este artigo é composto de duas partes:
- Novos recursos mais relevantes
Outros recursos foram adicionados às versões 5.3, 5.4, 5.5, 5.6 e 7.0 do PHP (observe que não há PHP 6) e exploraremos os mais relevantes. - Construindo um software melhor
Analisaremos mais detalhadamente esses recursos e como eles podem nos ajudar a criar um software melhor.
Vamos começar explorando os “novos” recursos do PHP.
Classes, OOP, SOLID e padrões de design
Classes e objetos foram adicionados ao PHP 5, então o WordPress já faz uso desses recursos, no entanto, não de forma muito extensa ou abrangente: O paradigma de codificação no WordPress é principalmente programação funcional (realizando cálculos chamando funções desprovidas de estado do aplicativo) em vez de objeto programação orientada (OOP) (realização de cálculos manipulando o estado dos objetos). Por isso, também descrevo classes e objetos e como usá-los através da POO.
OOP é ideal para a produção de aplicações modulares: As classes permitem a criação de componentes, cada um dos quais pode implementar uma funcionalidade específica e interagir com outros componentes, e pode fornecer customização por meio de suas propriedades encapsuladas e herança, permitindo um alto grau de reutilização de código. Como consequência, o aplicativo é mais barato para testar e manter, pois recursos individuais podem ser isolados do aplicativo e tratados por conta própria; há também um aumento de produtividade, pois o desenvolvedor pode usar componentes já desenvolvidos e evitar reinventar a roda para cada aplicação.
Uma classe tem propriedades e funções, que podem receber visibilidade usando private
(acessível apenas de dentro da classe definidora), protected
(acessível de dentro da classe definidora e seu ancestral e classes herdadas) e public
(acessível de qualquer lugar). De dentro de uma função, podemos acessar as propriedades da classe prefixando seus nomes com $this->
:
class Person { protected $name; public function __construct($name) { $this->name = $name; } public function getIntroduction() { return sprintf( __('My name is %s'), $this->name ); } }
Uma classe é instanciada em um objeto através da palavra-chave new
, após a qual podemos acessar suas propriedades e funções através de ->
:
$person = new Person('Pedro'); echo $person->getIntroduction(); // This prints "My name is Pedro"
Uma classe herdada pode substituir as funções public
e protected
de suas classes ancestrais e acessar as funções ancestrais anexando-as com parent::
:
class WorkerPerson extends Person { protected $occupation; public function __construct($name, $occupation) { parent::__construct($name); $this->occupation = $occupation; } public function getIntroduction() { return sprintf( __('%s and my occupation is %s'), parent::getIntroduction(), $this->occupation ); } } $worker = new WorkerPerson('Pedro', 'web development'); echo $worker->getIntroduction(); // This prints "My name is Pedro and my occupation is web development"
Um método pode ser abstract
, o que significa que ele deve ser implementado por uma classe herdada. Uma classe contendo um método abstract
deve se tornar abstract
, significando que não pode ser instanciada; apenas a classe que implementa o método abstrato pode ser instanciada:
abstract class Person { abstract public function getName(); public function getIntroduction() { return sprintf( __('My name is %s'), $this->getName() ); } } // Person cannot be instantiated class Manuel extends Person { public function getName() { return 'Manuel'; } } // Manuel can be instantiated $manuel = new Manuel();
As classes também podem definir métodos e propriedades static
, que vivem sob a própria classe e não sob uma instanciação da classe como um objeto. Estes são acessados através de self::
de dentro da classe, e através do nome da classe + ::
de fora dela:
class Factory { protected static $instances = []; public static function registerInstance($handle, $instance) { self::$instances[$handle] = $instance; } public static function getInstance($handle) { return self::$instances[$handle]; } } $engine = Factory::getInstance('Engine');
Para tirar o máximo proveito da OOP, podemos usar os princípios SOLID para estabelecer uma base sólida e facilmente personalizável para o aplicativo e padrões de design para resolver problemas específicos de maneira testada e comprovada. Os padrões de design são padronizados e bem documentados, permitindo que os desenvolvedores entendam como os diferentes componentes do aplicativo se relacionam e fornecem uma maneira de estruturar o aplicativo de maneira ordenada, o que ajuda a evitar o uso de variáveis globais (como global $wpdb
) que poluem o meio ambiente global.
Namespaces
Namespaces foram adicionados ao PHP 5.3, portanto, eles estão totalmente ausentes do núcleo do WordPress.
Os namespaces permitem organizar a base de código estruturalmente para evitar conflitos quando itens diferentes têm o mesmo nome — de maneira semelhante aos diretórios do sistema operacional que permitem ter arquivos diferentes com o mesmo nome, desde que sejam armazenados em diretórios diferentes. Namespaces fazem o mesmo truque de encapsulamento para itens PHP (como classes, traits e interfaces) evitando colisões quando itens diferentes têm o mesmo nome, colocando-os em namespaces diferentes.
Os namespaces são obrigatórios ao interagir com bibliotecas de terceiros, pois não podemos controlar como seus itens serão nomeados, levando a possíveis colisões ao usar nomes padrão como "Arquivo", "Logger" ou "Uploader" para nossos itens. Além disso, mesmo dentro de um único projeto, os namespaces evitam que os nomes das classes se tornem extremamente longos para evitar conflitos com outras classes, o que poderia resultar em nomes como “MyProject_Controller_FileUpload”.
Os namespaces são definidos usando a palavra-chave namespace
(colocada na linha imediatamente após a abertura <?php
) e podem abranger vários níveis ou subnamespaces (semelhante a ter vários subdiretórios onde colocar um arquivo), que são separados usando um \
:
<?php namespace CoolSoft\ImageResizer\Controllers; class ImageUpload { }
Para acessar a classe acima, precisamos qualificar totalmente seu nome, incluindo seu namespace (e começando com \
):
$imageUpload = new \CoolSoft\ImageResizer\Controllers\ImageUpload();
Ou também podemos importar a classe para o contexto atual, após o qual podemos referenciar a classe diretamente pelo nome:
use CoolSoft\ImageResizer\Controllers\ImageUpload; $imageUpload = new ImageUpload();
Ao nomear namespaces seguindo convenções estabelecidas, podemos obter benefícios adicionais. Por exemplo, seguindo a Recomendação de Padrões do PHP PSR-4, o aplicativo pode usar o mecanismo de carregamento automático do Composer para carregar arquivos, diminuindo assim a complexidade e adicionando interoperabilidade sem atrito entre as dependências. Esta convenção estabelece incluir o nome do fornecedor (por exemplo, o nome da empresa) como o subnamespace superior, opcionalmente seguido pelo nome do pacote, e só então seguido por uma estrutura interna na qual cada subnamespace corresponde a um diretório com o mesmo nome. O resultado mapeia de 1 para 1 a localização física do arquivo na unidade com o namespace do elemento definido no arquivo.
Características
As características foram adicionadas ao PHP 5.4, portanto, atualmente estão ausentes do núcleo do WordPress.
O PHP suporta herança única, então uma subclasse é derivada de uma única classe pai, e não de várias. Portanto, classes que não se estendem umas das outras não podem reutilizar código por meio de herança de classe. Traits é um mecanismo que possibilita a composição horizontal de comportamento, possibilitando a reutilização de código entre classes que vivem em diferentes hierarquias de classes.
Um traço é semelhante a uma classe, no entanto, não pode ser instanciado por conta própria. Em vez disso, o código definido dentro de uma característica pode ser pensado como sendo “copiado e colado” na classe de composição em tempo de compilação.
Uma característica é definida usando a palavra-chave trait
, após a qual pode ser importada para qualquer classe por meio da palavra-chave use
. No exemplo abaixo, duas classes completamente não relacionadas Person
e Shop
podem reutilizar o mesmo código através de um trait Addressable
:
trait Addressable { protected $address; public function getAddress() { return $this->address; } public function setAddress($address) { $this->address = $address; } } class Person { use Addressable; } class Shop { use Addressable; } $person = new Person('Juan Carlos'); $person->setAddress('Obelisco, Buenos Aires');
Uma classe também pode compor mais de uma característica:
trait Exportable { public class exportToCSV($filename) { // Iterate all properties and export them to a CSV file } } class Person { use Addressable, Exportable; }
Os traços também podem ser compostos por outros traços, definir métodos abstratos e oferecer um mecanismo de resolução de conflitos quando dois ou mais traços compostos possuem o mesmo nome de função, entre outros recursos.
Interfaces
As interfaces foram adicionadas ao PHP 5, então o WordPress já faz uso desse recurso, porém com extrema moderação: o núcleo inclui menos de dez interfaces no total!
As interfaces permitem a criação de código que especifica quais métodos devem ser implementados, mas sem precisar definir como esses métodos são realmente implementados. Eles são úteis para definir contratos entre componentes, o que leva a uma melhor modularidade e manutenibilidade do aplicativo: uma classe que implementa uma interface pode ser uma caixa preta de código e, desde que as assinaturas das funções na interface não mudem, a o código pode ser atualizado à vontade sem produzir alterações significativas, o que pode ajudar a evitar o acúmulo de dívida técnica. Além disso, eles podem ajudar a reduzir o aprisionamento do fornecedor, permitindo trocar a implementação de alguma interface pela de um fornecedor diferente. Como consequência, é imperativo codificar o aplicativo em relação a interfaces em vez de implementações (e definir quais são as implementações reais por meio de injeção de dependência).
As interfaces são definidas usando a palavra-chave interface
, e devem listar apenas a assinatura de seus métodos (ou seja, sem ter seu conteúdo definido), que deve ter visibilidade public
(por padrão, adicionar nenhuma palavra-chave de visibilidade também a torna pública):
interface FileStorage { function save($filename, $contents); function readContents($filename); }
Uma classe define que implementa a interface através da palavra-chave implements
:
class LocalDriveFileStorage implements FileStorage { function save($filename, $contents) { // Implement logic } function readContents($filename) { // Implement logic } }
Uma classe pode implementar mais de uma interface, separando-as com ,
:
interface AWSService { function getRegion(); } class S3FileStorage implements FileStorage, AWSService { function save($filename, $contents) { // Implement logic } function readContents($filename) { // Implement logic } function getRegion() { return 'us-east-1'; } }
Como uma interface declara a intenção do que um componente deve fazer, é extremamente importante nomear as interfaces apropriadamente.
Fechamentos
Closures foram adicionados ao PHP 5.3, portanto, eles estão totalmente ausentes do núcleo do WordPress.
Closures é um mecanismo para implementar funções anônimas, que ajuda a organizar o namespace global de funções de uso único (ou raramente usadas). Tecnicamente falando, closures são instâncias da classe Closure
, no entanto, na prática, provavelmente podemos estar alegremente inconscientes desse fato sem nenhum dano.
Antes dos closures, sempre que passávamos uma função como argumento para outra função, tínhamos que definir a função antecipadamente e passar seu nome como argumento:
function duplicate($price) { return $price*2; } $touristPrices = array_map('duplicate', $localPrices);
Com closures, uma função anônima (ou seja, sem nome) já pode ser passada diretamente como parâmetro:
$touristPrices = array_map(function($price) { return $price*2; }, $localPrices);
Closures podem importar variáveis para seu contexto através da palavra-chave use
:
$factor = 2; $touristPrices = array_map(function($price) use($factor) { return $price*$factor; }, $localPrices);
Geradores
Os geradores foram adicionados ao PHP 5.5, portanto, eles estão totalmente ausentes do núcleo do WordPress.
Os geradores fornecem uma maneira fácil de implementar iteradores simples. Um gerador permite escrever código que usa foreach
para iterar sobre um conjunto de dados sem a necessidade de construir um array na memória. Uma função geradora é igual a uma função normal, exceto que, em vez de retornar uma vez, ela pode yield
quantas vezes forem necessárias para fornecer os valores a serem iterados.
function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { yield $i; } } foreach (xrange(1, 9, 2) as $number) { echo "$number "; } // This prints: 1 3 5 7 9
Declarações de tipo de argumento e retorno
Diferentes declarações de tipo de argumento foram introduzidas em diferentes versões do PHP: WordPress já é capaz de declarar interfaces e arrays (o que não acontece: eu mal encontrei uma instância de uma função declarando um array como parâmetro no núcleo, e nenhuma interface) em breve será capaz de declarar callables (adicionados no PHP 5.4) e tipos escalares: bool, float, int e string (adicionados no PHP 7.0). Declarações de tipo de retorno foram adicionadas ao PHP 7.0.
As declarações de tipo de argumento permitem que as funções declarem de que tipo específico um argumento deve ser. A validação é executada no momento da chamada, lançando uma exceção se o tipo do argumento não for o declarado. Declarações de tipo de retorno são o mesmo conceito, porém, elas especificam o tipo de valor que será retornado da função. As declarações de tipo são úteis para tornar a intenção da função mais fácil de entender e evitar erros de tempo de execução ao receber ou retornar um tipo inesperado.
O tipo de argumento é declarado antes do nome da variável do argumento e o tipo de retorno é declarado após os argumentos, precedido por :
:
function foo(boolean $bar): int { }
As declarações de tipo de argumento escalar têm duas opções: coercitiva e estrita. No modo coercitivo, se o tipo errado for passado como parâmetro, ele será convertido para o tipo certo. Por exemplo, uma função que recebe um inteiro para um parâmetro que espera uma string obterá uma variável do tipo string. No modo estrito, apenas uma variável do tipo exato de declaração será aceita.
O modo coercitivo é o padrão. Para habilitar o modo estrito, devemos adicionar uma instrução declare
usada com a declaração strict_types
:

declare(strict_types=1); function foo(boolean $bar) { }
Nova sintaxe e operadores
O WordPress já pode identificar listas de argumentos de comprimento variável por meio da função func_num_args
. A partir do PHP 5.6, podemos usar o token ...
para denotar que a função aceita um número variável de argumentos, e esses argumentos serão passados para a variável fornecida como um array:
function sum(...$numbers) { $sum = 0; foreach ($numbers as $number) { $sum += $number; } return $sum; }
A partir do PHP 5.6, constantes podem envolver expressões escalares envolvendo literais numéricos e string em vez de apenas valores estáticos, e também arrays:
const SUM = 37 + 2; // A scalar expression const LETTERS = ['a', 'b', 'c']; // An array
A partir do PHP 7.0, arrays também podem ser definidos usando define
:
define('LETTERS', ['a', 'b', 'c']);
O PHP 7.0 adicionou alguns novos operadores: o operador Null coalescing ( ??
) e o operador Spaceship ( <=>
).
O operador de coalescência nulo ??
é açúcar sintático para o caso comum de precisar usar um ternário em conjunto com isset(). Retorna seu primeiro operando se existir e não for NULL; caso contrário, ele retorna seu segundo operando.
$username = $_GET['user'] ?? 'nobody'; // This is equivalent to: // $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
O operador Spaceship <=>
é usado para comparar duas expressões, retornando -1, 0 ou 1 quando o primeiro operando for respectivamente menor, igual ou maior que o segundo operando.
echo 1 <=> 2; // returns -1 echo 1 <=> 1; // returns 0 echo 2 <=> 1; // returns 1
Esses são os novos recursos mais importantes adicionados ao PHP abrangendo as versões 5.3 a 7.0. A lista dos novos recursos adicionais, não listados neste artigo, pode ser obtida navegando na documentação do PHP sobre como migrar de versão para versão.
Em seguida, analisamos como podemos tirar o máximo proveito de todos esses novos recursos e das tendências recentes no desenvolvimento da Web para produzir um software melhor.
Recomendações de padrões PHP
O PHP Standards Recommendations foi criado por um grupo de desenvolvedores PHP de frameworks e bibliotecas populares, tentando estabelecer convenções para que diferentes projetos possam ser integrados de forma mais transparente e diferentes equipes possam trabalhar melhor entre si. As recomendações não são estáticas: as recomendações existentes podem ser preteridas e as mais recentes criadas para substituí-las, e novas são lançadas continuamente.
As recomendações atuais são as seguintes:
Grupo | Recomendação | Descrição |
---|---|---|
Estilos de codificação A formatação padronizada reduz o atrito cognitivo ao ler o código de outros autores | PSR-1 | Padrão Básico de Codificação |
PSR-2 | Guia de estilo de codificação | |
Carregamento automático Os carregadores automáticos removem a complexidade de incluir arquivos mapeando namespaces para caminhos do sistema de arquivos | PSR-4 | Carregamento automático aprimorado |
Interfaces As interfaces simplificam o compartilhamento de código entre projetos seguindo os contratos esperados | PSR-3 | Interface do registrador |
PSR-6 | Interface de cache | |
PSR-11 | Interface do Contêiner | |
PSR-13 | Links de hipermídia | |
PSR-16 | Cache Simples | |
HTTP Padrões e interfaces interoperáveis para ter uma abordagem agnóstica para lidar com solicitações e respostas HTTP, tanto no lado do cliente quanto no lado do servidor | PSR-7 | Interfaces de mensagens HTTP |
PSR-15 | Manipuladores HTTP | |
PSR-17 | Fábricas HTTP | |
PSR-18 | Cliente HTTP |
Pense e codifique em componentes
Os componentes tornam possível usar os melhores recursos de uma estrutura sem ficar preso à própria estrutura. Por exemplo, o Symfony foi lançado como um conjunto de componentes PHP reutilizáveis que podem ser instalados independentemente do framework Symfony; Laravel, outro framework PHP, faz uso de vários componentes Symfony, e lançou seu próprio conjunto de componentes reutilizáveis que podem ser usados por qualquer projeto PHP.
Todos esses componentes são publicados no Packagist, um repositório de pacotes PHP públicos, e podem ser facilmente adicionados a qualquer projeto PHP através do Composer, um gerenciador de dependências extremamente popular para PHP.
O WordPress deve fazer parte de um ciclo de desenvolvimento tão virtuoso. Infelizmente, o próprio núcleo do WordPress não é construído usando componentes (como evidenciado pela quase total ausência de interfaces) e, além disso, nem sequer possui o arquivo composer.json necessário para habilitar a instalação do WordPress através do Composer. Isso ocorre porque a comunidade WordPress não concordou se o WordPress é uma dependência de um site (nesse caso, instalá-lo através do Composer seria justificado) ou se é o próprio site (nesse caso, o Composer pode não ser a ferramenta certa para o trabalho) .
Na minha opinião, se esperamos que o WordPress permaneça relevante pelos próximos quinze anos (pelo menos o WordPress como um CMS de back-end), então o WordPress deve ser reconhecido como uma dependência do site e disponibilizado para instalação através do Composer . A razão é muito simples: com apenas um único comando no terminal, o Composer permite declarar e instalar as dependências de um projeto dos milhares de pacotes publicados no Packagist, tornando possível criar aplicativos PHP extremamente poderosos em pouco tempo, e os desenvolvedores adoram trabalhando desta forma. Se o WordPress não se adaptar a esse modelo, pode perder o suporte da comunidade de desenvolvimento e cair no esquecimento, tanto quanto o FTP caiu em desuso após a introdução de implantações baseadas em Git.
Eu diria que o lançamento do Gutenberg já demonstra que o WordPress é uma dependência do site e não o site em si: Gutenberg trata o WordPress como um CMS headless, e pode operar com outros sistemas backend também, como Drupal Gutenberg exemplifica. Portanto, Gutenberg deixa claro que o CMS que alimenta um site pode ser trocável, portanto, deve ser tratado como uma dependência. Além disso, o próprio Gutenberg se destina a ser baseado em componentes JavaScript lançados através do npm (como explicado pelo core committer Adam Silverstein), então se espera-se que o cliente WordPress gerencie seus pacotes JavaScript através do gerenciador de pacotes npm, então por que não estender essa lógica para o backend para gerenciar as dependências do PHP através do Composer?
Agora a boa notícia: Não há necessidade de esperar que este problema seja resolvido, pois já é possível tratar o WordPress como dependência de um site e instalá-lo através do Composer. John P. Bloch espelhou o núcleo do WordPress no Git, adicionou um arquivo composer.json e o lançou no Packagist, e o Roots' Bedrock fornece um pacote para instalar o WordPress com uma estrutura de pastas personalizada com suporte para ferramentas de desenvolvimento modernas e segurança aprimorada. E temas e plugins também são abordados; desde que tenham sido listados nos diretórios de temas e plugins do WordPress, eles estão disponíveis no WordPress Packagist.
Como consequência, é uma opção sensata criar código WordPress não pensando em termos de temas e plugins, mas pensando em termos de componentes, disponibilizando-os através do Packagist para serem usados por qualquer projeto PHP, e adicionalmente empacotados e lançados como temas e plugins para uso específico do WordPress. Se o componente precisar interagir com as APIs do WordPress, essas APIs podem ser abstraídas por trás de uma interface que, se necessário, também pode ser implementada para outros CMSs.
Adicionando um mecanismo de modelo para melhorar a camada de visualização
Se seguirmos a recomendação de pensar e codificar em componentes e tratarmos o WordPress como uma dependência do site que não seja o próprio site, nossos projetos poderão se libertar dos limites impostos pelo WordPress e importar ideias e ferramentas extraídas de outros frameworks.
A renderização de conteúdo HTML no lado do servidor é um exemplo disso, que é feito por meio de modelos PHP simples. Essa camada de visualização pode ser aprimorada através dos mecanismos de template Twig (do Symfony) e Blade (do Laravel), que fornecem uma sintaxe muito concisa e recursos poderosos que lhe dão uma vantagem sobre os templates PHP simples. Em particular, os blocos dinâmicos do Gutenberg podem se beneficiar facilmente desses mecanismos de modelo, já que seu processo de renderização do HTML do bloco no lado do servidor é desacoplado da arquitetura de hierarquia de modelos do WordPress.
Arquiteto O Aplicativo Para Uso Geral
Codificar contra interfaces e pensar em termos de componentes nos permite arquitetar um aplicativo para uso geral e personalizá-lo para o uso específico que precisamos entregar, em vez de codificar apenas para o uso específico de cada projeto que temos. Embora essa abordagem seja mais cara no curto prazo (envolve trabalho extra), vale a pena no longo prazo quando projetos adicionais podem ser entregues com menos esforços de apenas personalizar um aplicativo de uso geral.
Para que esta abordagem seja eficaz, as seguintes considerações devem ser levadas em consideração:
Evite dependências fixas (tanto quanto possível)
jQuery e Bootstrap (ou Foundation, ou <–insira sua biblioteca favorita aqui–> ) poderiam ter sido considerados indispensáveis alguns anos atrás, no entanto, eles vêm perdendo terreno contra o vanilla JS e recursos CSS nativos mais recentes. Portanto, um projeto de uso geral codificado há cinco anos e que dependia dessas bibliotecas pode não ser mais adequado hoje em dia. Portanto, como regra geral, quanto menor a quantidade de dependências fixas em bibliotecas de terceiros, mais atualizada ela se mostrará a longo prazo.
Melhoria progressiva das funcionalidades
O WordPress é um sistema CMS completo que inclui gerenciamento de usuários, portanto, o suporte para gerenciamento de usuários está incluído imediatamente. No entanto, nem todo site WordPress requer gerenciamento de usuários. Portanto, nosso aplicativo deve levar isso em consideração e trabalhar de maneira ideal em cada cenário: apoiar o gerenciamento de usuários sempre que necessário, mas não carregar os ativos correspondentes quando não for necessário. Essa abordagem também pode funcionar gradualmente: digamos que um cliente precise implementar um formulário de contato, mas não tenha orçamento, então o codificamos usando um plug-in gratuito com recursos limitados e outro cliente tem orçamento para comprar a licença de uma oferta de plug-in comercial melhores características. Então, podemos codificar nossa funcionalidade para padronizar uma funcionalidade muito básica e usar cada vez mais os recursos do plug-in mais capaz disponível no sistema.
Revisão Contínua de Código e Documentação
Ao revisar periodicamente nosso código escrito anteriormente e sua documentação, podemos validar se ele está atualizado em relação às novas convenções e tecnologias e, se não estiver, tomar medidas para atualizá-lo antes que a dívida técnica se torne muito cara para ser superada e precisamos codificar tudo de novo do zero.
Leitura recomendada : Fique atento: Funções PHP e WordPress que podem tornar seu site inseguro
Tente minimizar os problemas, mas esteja preparado quando eles acontecerem
Nenhum software é 100% perfeito: os bugs estão sempre lá, só não os encontramos ainda. Como tal, precisamos garantir que, uma vez que os problemas surjam, eles sejam fáceis de corrigir.
Simplifique
Um software complexo não pode ser mantido a longo prazo: não apenas porque outros membros da equipe podem não entendê-lo, mas também porque a pessoa que o codificou pode não entender seu próprio código complexo daqui a alguns anos. Portanto, produzir softwares simples deve ser uma prioridade, mais ainda, pois somente softwares simples podem ser corretos e rápidos.
Falhar no tempo de compilação é melhor do que no tempo de execução
Se uma parte do código puder ser validada contra erros em tempo de compilação ou em tempo de execução, devemos priorizar a solução de tempo de compilação, para que o erro possa surgir e ser tratado no estágio de desenvolvimento e antes que o aplicativo chegue à produção. Por exemplo, const
e define
são usados para definir constantes, no entanto, enquanto const
é validado em tempo de compilação, define
é validado em tempo de execução. Portanto, sempre que possível, usar const
é preferível a define
.
Seguindo essa recomendação, a conexão de funções do WordPress contidas em classes pode ser aprimorada passando a classe real como um parâmetro em vez de uma string com o nome da classe. No exemplo abaixo, se a classe Foo
for renomeada, enquanto o segundo gancho produzirá um erro de compilação, o primeiro gancho falhará em tempo de execução, portanto, o segundo gancho é melhor:
class Foo { public static function bar() { } } add_action('init', ['Foo', 'bar']); // Not so good add_action('init', [Foo::class, 'bar']); // Much better
Pelo mesmo motivo acima, devemos evitar o uso de variáveis globais (como global $wpdb
): elas não apenas poluem o contexto global e não são fáceis de rastrear de onde se originam, mas também, se forem renomeadas, o erro será ser produzido em tempo de execução. Como solução, podemos usar um Dependency Injection Container para obter uma instância do objeto necessário.
Lidando com Erros/Exceções
Podemos criar uma arquitetura de objetos Exception
, para que a aplicação possa reagir apropriadamente de acordo com cada problema em particular, para recuperar dele sempre que possível ou mostrar uma mensagem de erro útil para o usuário sempre que não, e em geral para registrar o erro para o administrador para corrigir o problema. E sempre proteja seus usuários da tela branca da morte: Todos os Error
e Exception
não capturados podem ser interceptados através da função set_exception_handler
para imprimir uma mensagem de erro não assustadora na tela.
Adote ferramentas de compilação
As ferramentas de construção podem economizar muito tempo automatizando tarefas que são muito tediosas para executar manualmente. O WordPress não oferece integração com nenhuma ferramenta de compilação específica, portanto, a tarefa de incorporá-las ao projeto caberá inteiramente ao desenvolvedor.
Existem diferentes ferramentas para realizar diferentes propósitos. Por exemplo, existem ferramentas de compilação para executar tarefas de compactação e redimensionamento de imagens, minimização de arquivos JS e CSS e cópia de arquivos para um diretório para a produção de uma versão, como Webpack, Grunt e Gulp; outras ferramentas ajudam a criar o scaffolding de um projeto, o que é útil para produzir a estrutura de pastas para nossos temas ou plugins, como o Yeoman. De fato, com tantas ferramentas ao redor, navegar pelos artigos comparando as diferentes ferramentas disponíveis ajudará a encontrar a mais adequada às nossas necessidades.
Em alguns casos, no entanto, não existem ferramentas de compilação que possam alcançar exatamente o que nosso projeto precisa, portanto, podemos precisar codificar nossa própria ferramenta de compilação como uma extensão do próprio projeto. Por exemplo, fiz isso para gerar o arquivo service-worker.js para adicionar suporte para Service Workers no WordPress.
Conclusão
Devido à sua forte ênfase em manter a compatibilidade com versões anteriores, estendida até o PHP 5.2.4, o WordPress não conseguiu se beneficiar dos recursos mais recentes adicionados ao PHP, e esse fato fez com que o WordPress se tornasse uma plataforma não muito empolgante para codificar para entre muitos desenvolvedores.
Felizmente, esses dias sombrios podem acabar em breve, e o WordPress pode se tornar uma plataforma brilhante e empolgante para codificar mais uma vez: o requisito do PHP 7.0+ a partir de dezembro de 2019 disponibilizará muitos recursos do PHP, permitindo que os desenvolvedores produzam mais poderosos e software mais eficiente. Neste artigo, revisamos os recursos PHP recém-disponíveis mais importantes e como aproveitá-los ao máximo.
O recente lançamento do Gutenberg pode ser um sinal dos bons tempos que virão: mesmo que o próprio Gutenberg não tenha sido totalmente aceito pela comunidade, pelo menos demonstra uma vontade de incorporar as tecnologias mais recentes (como React e Webpack) no núcleo . Essa reviravolta me faz pensar: se o front-end pode receber uma reforma tão grande, por que não estendê-lo para o back-end? Uma vez que o WordPress requer pelo menos PHP 7.0, a atualização para ferramentas e metodologias modernas pode acelerar: Por mais que o npm tenha se tornado o gerenciador de pacotes JavaScript preferido, por que não tornar o Composer o gerenciador de dependências oficial do PHP? Se os blocos são a nova unidade para construir sites no frontend, por que não usar componentes PHP como a unidade para incorporar funcionalidades no backend? E, finalmente, se Gutenberg trata o WordPress como um CMS de back-end trocável, por que não reconhecer que o WordPress é uma dependência do site e não o próprio site? Vou deixar essas questões em aberto para você refletir e ponderar.