Miglioramento del codice WordPress con PHP moderno
Pubblicato: 2022-03-10WordPress è nato quindici anni fa e, poiché storicamente ha conservato la compatibilità con le versioni precedenti, le versioni più recenti del suo codice non potevano sfruttare appieno le ultime funzionalità offerte dalle versioni più recenti di PHP. Sebbene l'ultima versione di PHP sia la 7.3.2, WordPress offre ancora supporto fino a PHP 5.2.4.
Ma quei giorni finiranno presto! WordPress aggiornerà il supporto minimo della versione PHP, aumentando fino a PHP 5.6 ad aprile 2019 e PHP 7 a dicembre 2019 (se tutto va secondo i piani). Possiamo quindi finalmente iniziare a utilizzare le capacità di programmazione imperative di PHP senza timore di danneggiare i siti dei nostri clienti. Evviva!
Poiché i quindici anni di codice funzionale di WordPress hanno influenzato il modo in cui gli sviluppatori hanno costruito con WordPress, i nostri siti, temi e plug-in potrebbero essere disseminati di codice non ottimale che può ricevere volentieri un aggiornamento.
Questo articolo è composto da due parti:
- Nuove funzionalità più rilevanti
Ulteriori funzionalità sono state aggiunte alle versioni PHP 5.3, 5.4, 5.5, 5.6 e 7.0 (notare che non esiste PHP 6) ed esploreremo quelle più rilevanti. - Costruire un software migliore
Daremo un'occhiata più da vicino a queste funzionalità e a come sono in grado di aiutarci a creare software migliore.
Iniziamo esplorando le “nuove” funzionalità di PHP.
Classi, OOP, SOLID e modelli di design
Classi e oggetti sono stati aggiunti a PHP 5, quindi WordPress utilizza già queste funzionalità, tuttavia, non in modo molto estensivo o completo: il paradigma della codifica in WordPress è principalmente la programmazione funzionale (esecuzione di calcoli chiamando funzioni prive di stato dell'applicazione) anziché l'oggetto programmazione orientata (OOP) (esecuzione di calcoli manipolando lo stato degli oggetti). Quindi descrivo anche classi e oggetti e come usarli tramite OOP.
OOP è ideale per la produzione di applicazioni modulari: le classi consentono la creazione di componenti, ognuno dei quali può implementare una funzionalità specifica e interagire con altri componenti, e può fornire la personalizzazione attraverso le sue proprietà incapsulate e l'ereditarietà, consentendo un alto grado di riutilizzabilità del codice. Di conseguenza, l'applicazione è più economica da testare e mantenere, poiché le singole funzionalità possono essere isolate dall'applicazione e gestite da sole; c'è anche un aumento della produttività poiché lo sviluppatore può utilizzare componenti già sviluppati ed evitare di reinventare la ruota per ogni applicazione.
Una classe ha proprietà e funzioni, a cui è possibile dare visibilità utilizzando private
(accessibile solo dall'interno della classe di definizione), protected
(accessibile dall'interno della classe di definizione e delle sue classi antenate ed ereditarie) e public
(accessibile da qualsiasi luogo). Dall'interno di una funzione, possiamo accedere alle proprietà della classe anteponendo i loro nomi con $this->
:
class Person { protected $name; public function __construct($name) { $this->name = $name; } public function getIntroduction() { return sprintf( __('My name is %s'), $this->name ); } }
Una classe viene istanziata in un oggetto tramite la new
parola chiave, dopodiché possiamo accedere alle sue proprietà e funzioni tramite ->
:
$person = new Person('Pedro'); echo $person->getIntroduction(); // This prints "My name is Pedro"
Una classe ereditante può sovrascrivere le funzioni public
e protected
dalle sue classi predecessore e accedere alle funzioni predecessore anteponendole con 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"
Un metodo può essere reso abstract
, il che significa che deve essere implementato da una classe ereditaria. Una classe contenente un metodo abstract
deve essere resa essa stessa abstract
, il che significa che non può essere istanziata; solo la classe che implementa il metodo astratto può essere istanziata:
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();
Le classi possono anche definire metodi e proprietà static
, che risiedono sotto la classe stessa e non sotto un'istanza della classe come oggetto. Vi si accede tramite self::
dall'interno della classe, e tramite il nome della classe + ::
dall'esterno:
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');
Per ottenere il massimo da OOP, possiamo utilizzare i principi SOLID per stabilire una base solida ma facilmente personalizzabile per l'applicazione e modelli di progettazione per risolvere problemi specifici in un modo collaudato. I modelli di progettazione sono standardizzati e ben documentati, consentendo agli sviluppatori di comprendere in che modo i diversi componenti dell'applicazione si relazionano tra loro e forniscono un modo per strutturare l'applicazione in modo ordinato che aiuta a evitare l'uso di variabili globali (come global $wpdb
) che inquinano l'ambiente globale.
Spazi dei nomi
I namespace sono stati aggiunti a PHP 5.3, quindi attualmente mancano del tutto dal core di WordPress.
Gli spazi dei nomi consentono di organizzare strutturalmente la base di codice per evitare conflitti quando elementi diversi hanno lo stesso nome, in modo simile alle directory del sistema operativo che consentono di avere file diversi con lo stesso nome purché siano archiviati in directory diverse. Gli spazi dei nomi eseguono lo stesso trucco di incapsulamento per gli elementi PHP (come classi, tratti e interfacce) evitando collisioni quando elementi diversi hanno lo stesso nome posizionandoli su spazi dei nomi diversi.
Gli spazi dei nomi sono un must quando si interagisce con librerie di terze parti poiché non possiamo controllare come verranno nominati i loro elementi, portando a potenziali collisioni quando si utilizzano nomi standard come "File", "Logger" o "Uploader" per i nostri elementi. Inoltre, anche all'interno di un singolo progetto, gli spazi dei nomi evitano che i nomi delle classi diventino estremamente lunghi per evitare conflitti con altre classi, che potrebbero risultare in nomi come “MyProject_Controller_FileUpload”.
I namespace sono definiti usando la parola chiave namespace
(posizionata sulla riga subito dopo l'apertura <?php
) e possono estendersi su più livelli o sottospazi dei nomi (simile ad avere diverse sottodirectory dove posizionare un file), che sono separati usando un \
:
<?php namespace CoolSoft\ImageResizer\Controllers; class ImageUpload { }
Per accedere alla classe sopra, dobbiamo qualificare completamente il suo nome incluso il suo spazio dei nomi (e iniziando con \
):
$imageUpload = new \CoolSoft\ImageResizer\Controllers\ImageUpload();
Oppure possiamo anche importare la classe nel contesto corrente, dopodiché possiamo fare riferimento alla classe direttamente con il suo nome:
use CoolSoft\ImageResizer\Controllers\ImageUpload; $imageUpload = new ImageUpload();
Denominando gli spazi dei nomi seguendo convenzioni stabilite, possiamo ottenere ulteriori vantaggi. Ad esempio, seguendo la raccomandazione sugli standard PHP PSR-4, l'applicazione può utilizzare il meccanismo di caricamento automatico di Composer per caricare i file, diminuendo così la complessità e aggiungendo un'interoperabilità senza attriti tra le dipendenze. Questa convenzione prevede di includere il nome del venditore (es. il nome dell'azienda) come sottospazio dei nomi superiore, eventualmente seguito dal nome del pacchetto, e solo successivamente seguito da una struttura interna in cui ogni sottospazio dei nomi corrisponde ad una directory con lo stesso nome. Il risultato mappa da 1 a 1 la posizione fisica del file nell'unità con lo spazio dei nomi dell'elemento definito nel file.
Tratti
I tratti sono stati aggiunti a PHP 5.4, quindi attualmente mancano del tutto dal core di WordPress.
PHP supporta l'ereditarietà singola, quindi una sottoclasse è derivata da una singola classe genitore e non da più classi. Pertanto, le classi che non si estendono l'una dall'altra non possono riutilizzare il codice tramite l'ereditarietà delle classi. Traits è un meccanismo che consente la composizione orizzontale del comportamento, rendendo possibile il riutilizzo del codice tra classi che vivono in diverse gerarchie di classi.
Un tratto è simile a una classe, tuttavia non può essere istanziato da solo. Al contrario, il codice definito all'interno di un tratto può essere pensato come "copiato e incollato" nella classe di composizione al momento della compilazione.
Un tratto viene definito utilizzando la parola chiave trait
, dopodiché può essere importato in qualsiasi classe tramite la parola chiave use
. Nell'esempio seguente, due classi completamente indipendenti Person
e Shop
possono riutilizzare lo stesso codice attraverso un tratto 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');
Una classe può anche comporre più di un tratto:
trait Exportable { public class exportToCSV($filename) { // Iterate all properties and export them to a CSV file } } class Person { use Addressable, Exportable; }
I tratti possono anche essere composti da altri tratti, definire metodi astratti e offrire un meccanismo di risoluzione dei conflitti quando due o più tratti composti hanno lo stesso nome di funzione, tra le altre caratteristiche.
Interfacce
Le interfacce sono state aggiunte a PHP 5, quindi WordPress utilizza già questa funzionalità, tuttavia, con estrema parsimonia: il core include meno di dieci interfacce in totale!
Le interfacce consentono di creare codice che specifica quali metodi devono essere implementati, ma senza dover definire come questi metodi vengono effettivamente implementati. Sono utili per definire i contratti tra i componenti, il che porta a una migliore modularità e manutenibilità dell'applicazione: una classe che implementa un'interfaccia può essere una scatola nera di codice e finché le firme delle funzioni nell'interfaccia non cambiano, il il codice può essere aggiornato a piacimento senza produrre modifiche sostanziali, che possono aiutare a prevenire l'accumulo di debiti tecnici. Inoltre, possono aiutare a ridurre il blocco del fornitore, consentendo di scambiare l'implementazione di alcune interfacce con quella di un fornitore diverso. Di conseguenza, è imperativo codificare l'applicazione in base alle interfacce anziché alle implementazioni (e definire quali sono le implementazioni effettive tramite l'iniezione delle dipendenze).
Le interfacce sono definite usando la parola chiave interface
, e devono elencare solo la firma dei suoi metodi (cioè senza che ne siano definiti i contenuti), che devono avere visibilità public
(di default, l'aggiunta di nessuna parola chiave visibilità la rende anche pubblica):
interface FileStorage { function save($filename, $contents); function readContents($filename); }
Una classe definisce che implementa l'interfaccia tramite la parola chiave implements
:
class LocalDriveFileStorage implements FileStorage { function save($filename, $contents) { // Implement logic } function readContents($filename) { // Implement logic } }
Una classe può implementare più di un'interfaccia, separandole con ,
:
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'; } }
Poiché un'interfaccia dichiara l'intento di ciò che un componente dovrebbe fare, è estremamente importante nominare le interfacce in modo appropriato.
Chiusure
Le chiusure sono state aggiunte a PHP 5.3, quindi attualmente mancano del tutto dal core di WordPress.
Le chiusure sono un meccanismo per l'implementazione di funzioni anonime, che aiuta a declutter lo spazio dei nomi globale dalle funzioni monouso (o usate di rado). Tecnicamente parlando, le chiusure sono istanze della classe Closure
, tuttavia, in pratica, molto probabilmente possiamo essere beatamente inconsapevoli di questo fatto senza alcun danno.
Prima delle chiusure, ogni volta che si passava una funzione come argomento a un'altra funzione, dovevamo definire la funzione in anticipo e passare il suo nome come argomento:
function duplicate($price) { return $price*2; } $touristPrices = array_map('duplicate', $localPrices);
Con le chiusure, una funzione anonima (cioè senza nome) può già essere passata direttamente come parametro:
$touristPrices = array_map(function($price) { return $price*2; }, $localPrices);
Le chiusure possono importare variabili nel suo contesto tramite la parola chiave use
:
$factor = 2; $touristPrices = array_map(function($price) use($factor) { return $price*$factor; }, $localPrices);
Generatori
I generatori sono stati aggiunti a PHP 5.5, quindi attualmente mancano del tutto dal core di WordPress.
I generatori forniscono un modo semplice per implementare semplici iteratori. Un generatore consente di scrivere codice che utilizza foreach
per iterare su un insieme di dati senza dover creare un array in memoria. Una funzione generatore è la stessa di una funzione normale, tranne per il fatto che invece di restituire una volta, può yield
tutte le volte necessarie per fornire i valori su cui eseguire l'iterazione.
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
Dichiarazioni di argomento e tipo di ritorno
Diverse dichiarazioni di tipo di argomento sono state introdotte in diverse versioni di PHP: WordPress è già in grado di dichiarare interfacce e array (cosa che non fa: ho trovato a malapena un'istanza di una funzione che dichiara un array come parametro nel core e nessuna interfaccia) e lo farà presto sarà possibile dichiarare callable (aggiunti in PHP 5.4) e tipi scalari: bool, float, int e string (aggiunti in PHP 7.0). Le dichiarazioni del tipo di ritorno sono state aggiunte a PHP 7.0.
Le dichiarazioni del tipo di argomento consentono alle funzioni di dichiarare quale tipo specifico deve essere un argomento. La validazione viene eseguita al momento della chiamata, generando un'eccezione se il tipo dell'argomento non è quello dichiarato. Le dichiarazioni del tipo restituito sono lo stesso concetto, tuttavia specificano il tipo di valore che verrà restituito dalla funzione. Le dichiarazioni di tipo sono utili per rendere più facile la comprensione dell'intento della funzione e per evitare che errori di runtime ricevano o restituiscano un tipo imprevisto.
Il tipo di argomento viene dichiarato prima del nome della variabile di argomento e il tipo restituito viene dichiarato dopo gli argomenti, preceduto da :
:
function foo(boolean $bar): int { }
Le dichiarazioni del tipo di argomento scalare hanno due opzioni: coercitivo e rigoroso. In modalità coercitiva, se il tipo sbagliato viene passato come parametro, verrà convertito nel tipo corretto. Ad esempio, una funzione a cui viene assegnato un numero intero per un parametro che prevede una stringa otterrà una variabile di tipo string. In modalità rigorosa verrà accettata solo una variabile dell'esatto tipo di dichiarazione.
La modalità coercitiva è l'impostazione predefinita. Per abilitare la modalità rigorosa, dobbiamo aggiungere un'istruzione declare
utilizzata con la dichiarazione strict_types
:
declare(strict_types=1); function foo(boolean $bar) { }
Nuova sintassi e operatori
WordPress può già identificare elenchi di argomenti di lunghezza variabile tramite la funzione func_num_args
. A partire da PHP 5.6, possiamo usare il token ...
per denotare che la funzione accetta un numero variabile di argomenti, e questi argomenti verranno passati nella variabile data come un array:
function sum(...$numbers) { $sum = 0; foreach ($numbers as $number) { $sum += $number; } return $sum; }
A partire da PHP 5.6, le costanti possono coinvolgere espressioni scalari che coinvolgono valori numerici e stringhe anziché solo valori statici e anche array:
const SUM = 37 + 2; // A scalar expression const LETTERS = ['a', 'b', 'c']; // An array
A partire da PHP 7.0, gli array possono anche essere definiti utilizzando define
:
define('LETTERS', ['a', 'b', 'c']);
PHP 7.0 ha aggiunto un paio di nuovi operatori: l'operatore Null coalescing ( ??
) e l'operatore Spaceship ( <=>
).
L'operatore di coalescenza Null ??
è lo zucchero sintattico per il caso comune di dover usare un ternario insieme a isset(). Restituisce il suo primo operando se esiste e non è NULL; in caso contrario, restituisce il suo secondo operando.
$username = $_GET['user'] ?? 'nobody'; // This is equivalent to: // $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
L'operatore Spaceship <=>
viene utilizzato per confrontare due espressioni, restituendo -1, 0 o 1 quando il primo operando è rispettivamente minore, uguale o maggiore del secondo operando.
echo 1 <=> 2; // returns -1 echo 1 <=> 1; // returns 0 echo 2 <=> 1; // returns 1
Queste sono le nuove funzionalità più importanti aggiunte alle versioni PHP dalla 5.3 alla 7.0. L'elenco delle nuove funzionalità aggiuntive, non elencate in questo articolo, può essere ottenuto sfogliando la documentazione di PHP sulla migrazione da una versione all'altra.
Successivamente, analizziamo come possiamo ottenere il massimo da tutte queste nuove funzionalità e dalle recenti tendenze nello sviluppo web, per produrre software migliore.
Raccomandazioni sugli standard PHP
Le raccomandazioni sugli standard PHP sono state create da un gruppo di sviluppatori PHP provenienti da framework e librerie popolari, cercando di stabilire convenzioni in modo che i diversi progetti possano essere integrati in modo più fluido e diversi team possano lavorare meglio tra loro. Le raccomandazioni non sono statiche: le raccomandazioni esistenti possono essere deprecate e quelle nuove create per sostituirle e quelle nuove vengono rilasciate su base continuativa.
Le attuali raccomandazioni sono le seguenti:
Gruppo | Raccomandazione | Descrizione |
---|---|---|
Stili di codifica La formattazione standardizzata riduce l'attrito cognitivo durante la lettura del codice di altri autori | PSR-1 | Standard di codifica di base |
PSR-2 | Guida allo stile di codifica | |
Caricamento automatico I caricatori automatici eliminano la complessità dell'inclusione dei file mappando gli spazi dei nomi sui percorsi del file system | PSR-4 | Caricamento automatico migliorato |
Interfacce Le interfacce semplificano la condivisione del codice tra i progetti seguendo i contratti previsti | PSR-3 | Interfaccia del registratore |
PSR-6 | Interfaccia di memorizzazione nella cache | |
PSR-11 | Interfaccia del contenitore | |
PSR-13 | Collegamenti ipermediali | |
PSR-16 | Semplice cache | |
HTTP Standard e interfacce interoperabili per avere un approccio agnostico alla gestione di richieste e risposte HTTP, sia lato client che lato server | PSR-7 | Interfacce di messaggi HTTP |
PSR-15 | Gestori HTTP | |
PSR-17 | Fabbriche HTTP | |
PSR-18 | Client HTTP |
Pensa e codifica nei componenti
I componenti consentono di utilizzare le migliori funzionalità di un framework senza essere vincolati al framework stesso. Ad esempio, Symfony è stato rilasciato come un insieme di componenti PHP riutilizzabili che possono essere installati indipendentemente dal framework Symfony; Laravel, un altro framework PHP, utilizza diversi componenti Symfony e ha rilasciato il proprio set di componenti riutilizzabili che possono essere utilizzati da qualsiasi progetto PHP.
Tutti questi componenti sono pubblicati in Packagist, un repository di pacchetti PHP pubblici, e possono essere facilmente aggiunti a qualsiasi progetto PHP tramite Composer, un gestore di dipendenze estremamente popolare per PHP.
WordPress dovrebbe essere parte di un ciclo di sviluppo così virtuoso. Purtroppo il core di WordPress stesso non è costruito utilizzando componenti (come dimostra la quasi totale assenza di interfacce) e, inoltre, non ha nemmeno il file composer.json necessario per abilitare l'installazione di WordPress tramite Composer. Questo perché la community di WordPress non ha concordato se WordPress è una dipendenza di un sito (in tal caso sarebbe giustificato installarlo tramite Composer) o se è il sito stesso (in tal caso Composer potrebbe non essere lo strumento giusto per il lavoro) .
A mio parere, se dobbiamo aspettarci che WordPress rimanga rilevante per i prossimi quindici anni (almeno WordPress come CMS back-end), allora WordPress deve essere riconosciuto come dipendenza di un sito e reso disponibile per l'installazione tramite Composer . Il motivo è molto semplice: con a malapena un comando nel terminale, Composer consente di dichiarare e installare le dipendenze di un progetto dalle migliaia di pacchetti pubblicati in Packagist, rendendo possibile creare applicazioni PHP estremamente potenti in pochissimo tempo, e gli sviluppatori adorano lavorando in questo modo. Se WordPress non si adatta a questo modello, potrebbe perdere il supporto della comunità di sviluppo e cadere nell'oblio, tanto quanto FTP è caduto in disgrazia dopo l'introduzione delle implementazioni basate su Git.
Direi che il rilascio di Gutenberg dimostra già che WordPress è una dipendenza dal sito e non dal sito stesso: Gutenberg tratta WordPress come un CMS senza testa e può funzionare anche con altri sistemi di back-end, come esemplifica Drupal Gutenberg. Quindi, Gutenberg chiarisce che il CMS che alimenta un sito può essere scambiabile, quindi dovrebbe essere trattato come una dipendenza. Inoltre, lo stesso Gutenberg è concepito per essere basato su componenti JavaScript rilasciati tramite npm (come spiegato dal core committer Adam Silverstein), quindi se ci si aspetta che il client WordPress gestisca i suoi pacchetti JavaScript tramite il gestore di pacchetti npm, allora perché non estendere questa logica a il backend per gestire le dipendenze PHP tramite Composer?
Ora la buona notizia: non è necessario attendere che questo problema venga risolto poiché è già possibile trattare WordPress come una dipendenza di un sito e installarlo tramite Composer. John P. Bloch ha eseguito il mirroring del core di WordPress in Git, ha aggiunto un file composer.json e lo ha rilasciato in Packagist, e Bedrock di Roots fornisce un pacchetto per installare WordPress con una struttura di cartelle personalizzata con supporto per strumenti di sviluppo moderni e una maggiore sicurezza. E anche temi e plugin sono coperti; fintanto che sono stati elencati nelle directory dei temi e dei plugin di WordPress, sono disponibili in WordPress Packagist.
Di conseguenza, è un'opzione sensata creare codice WordPress non pensando in termini di temi e plugin, ma pensando in termini di componenti, rendendoli disponibili tramite Packagist per essere utilizzati da qualsiasi progetto PHP e inoltre impacchettati e rilasciati come temi e plugin per l'uso specifico di WordPress. Se il componente deve interagire con le API di WordPress, queste API possono essere astratte dietro un'interfaccia che, se necessario, può essere implementata anche per altri CMS.
Aggiunta di un motore di modelli per migliorare il livello di visualizzazione
Se seguiamo la raccomandazione di pensare e codificare nei componenti e trattiamo WordPress come una dipendenza di un sito diversa dal sito stesso, i nostri progetti possono liberarsi dai confini imposti da WordPress e importare idee e strumenti presi da altri framework.
Il rendering del contenuto HTML sul lato server è un esempio calzante, che viene eseguito tramite semplici modelli PHP. Questo livello di visualizzazione può essere migliorato attraverso i motori di template Twig (di Symfony) e Blade (di Laravel), che forniscono una sintassi molto concisa e potenti funzionalità che gli danno un vantaggio rispetto ai semplici template PHP. In particolare, i blocchi dinamici di Gutenberg possono facilmente trarre vantaggio da questi motori di modelli, poiché il loro processo di rendering dell'HTML del blocco sul lato server è disaccoppiato dall'architettura della gerarchia dei modelli di WordPress.
Architetto L'applicazione per l'uso generale
Codificare in base alle interfacce e pensare in termini di componenti ci consente di progettare un'applicazione per uso generale e personalizzarla per l'uso specifico che dobbiamo fornire, invece di codificare solo per l'uso specifico per ogni progetto che abbiamo. Anche se questo approccio è più costoso a breve termine (comporta lavoro extra), a lungo termine si ripaga quando è possibile fornire progetti aggiuntivi con sforzi inferiori rispetto alla semplice personalizzazione di un'applicazione di uso generale.
Affinché questo approccio sia efficace, è necessario tenere conto delle seguenti considerazioni:
Evita le dipendenze fisse (per quanto possibile)
jQuery e Bootstrap (o Foundation, o <–inserisci qui la tua libreria preferita–> ) avrebbero potuto essere considerati dei must-have alcuni anni fa, tuttavia, hanno costantemente perso terreno contro JS vanilla e le nuove funzionalità CSS native. Quindi, un progetto di uso generale codificato cinque anni fa che dipendeva da queste biblioteche potrebbe non essere più adatto al giorno d'oggi. Quindi, come regola generale, minore è la quantità di dipendenze fisse su librerie di terze parti, più aggiornato risulterà a lungo termine.
Miglioramento progressivo delle funzionalità
WordPress è un sistema CMS completo che include la gestione degli utenti, quindi il supporto per la gestione degli utenti è incluso immediatamente. Tuttavia, non tutti i siti WordPress richiedono la gestione degli utenti. Pertanto, la nostra applicazione dovrebbe tenerne conto e funzionare in modo ottimale su ogni scenario: supportare la gestione degli utenti ogni volta che è necessario, ma non caricare le risorse corrispondenti ogni volta che non lo è. Questo approccio può funzionare anche gradualmente: supponiamo che un cliente richieda di implementare un modulo Contattaci ma non abbia budget, quindi lo codifichiamo utilizzando un plug-in gratuito con funzionalità limitate e un altro cliente ha il budget per acquistare la licenza da un'offerta di plug-in commerciale caratteristiche migliori. Quindi, possiamo codificare la nostra funzionalità per impostazione predefinita su una funzionalità molto semplice e utilizzare sempre più le funzionalità di qualunque sia il plug-in più capace disponibile nel sistema.
Revisione continua del codice e della documentazione
Rivedendo periodicamente il nostro codice scritto in precedenza e la sua documentazione, possiamo convalidare se è aggiornato rispetto a nuove convenzioni e tecnologie e, in caso contrario, adottare misure per aggiornarlo prima che il debito tecnico diventi troppo costoso da superare e abbiamo bisogno di codificarlo di nuovo da zero.
Letture consigliate : Stai attento: funzioni PHP e WordPress che possono rendere insicuro il tuo sito
Cerca di ridurre al minimo i problemi, ma sii preparato quando accadono
Nessun software è mai perfetto al 100%: i bug ci sono sempre, solo che non li abbiamo ancora trovati. Pertanto, dobbiamo assicurarci che, una volta che si verificano i problemi, siano facili da risolvere.
Falla semplice
Il software complesso non può essere mantenuto a lungo termine: non solo perché altri membri del team potrebbero non capirlo, ma anche perché la persona che lo ha codificato potrebbe non comprendere il proprio codice complesso alcuni anni dopo. Quindi produrre software semplice deve essere una priorità, tanto più che solo un software semplice può essere corretto e veloce.
Non riuscire a compilare il tempo è meglio che a runtime
Se un pezzo di codice può essere convalidato rispetto agli errori in fase di compilazione o in fase di esecuzione, è necessario dare la priorità alla soluzione in fase di compilazione, in modo che l'errore possa verificarsi ed essere gestito nella fase di sviluppo e prima che l'applicazione raggiunga la produzione. Ad esempio, sia const
che define
vengono utilizzati per definire le costanti, tuttavia, mentre const
viene convalidato in fase di compilazione, define
viene convalidato in fase di esecuzione. Quindi, quando possibile, è preferibile utilizzare const
rispetto a define
.
Seguendo questa raccomandazione, è possibile migliorare l'aggancio delle funzioni di WordPress contenute nelle classi passando la classe effettiva come parametro anziché una stringa con il nome della classe. Nell'esempio seguente, se la classe Foo
viene rinominata, mentre il secondo hook produrrà un errore di compilazione, il primo hook fallirà in runtime, quindi il secondo hook è migliore:
class Foo { public static function bar() { } } add_action('init', ['Foo', 'bar']); // Not so good add_action('init', [Foo::class, 'bar']); // Much better
Per lo stesso motivo di cui sopra, dovremmo evitare di utilizzare variabili globali (come global $wpdb
): queste non solo inquinano il contesto globale e non sono facili da tracciare da dove provengono, ma anche, se vengono rinominate, l'errore essere prodotto in fase di esecuzione. Come soluzione, possiamo utilizzare un Dependency Injection Container per ottenere un'istanza dell'oggetto richiesto.
Gestire errori/eccezioni
Possiamo creare un'architettura di oggetti Exception
, in modo che l'applicazione possa reagire in modo appropriato in base a ogni particolare problema, per risolverlo quando possibile o mostrare un messaggio di errore utile all'utente ogni volta che non lo è, e in generale per registrare l'errore per il amministratore per risolvere il problema. E proteggi sempre i tuoi utenti dalla schermata bianca della morte: tutti gli Error
e le Exception
non rilevati possono essere intercettati tramite la funzione set_exception_handler
per stampare un messaggio di errore non spaventoso sullo schermo.
Adotta strumenti di costruzione
Gli strumenti di compilazione possono far risparmiare molto tempo automatizzando attività che sono molto noiose da eseguire manualmente. WordPress non offre integrazione con nessuno strumento di costruzione specifico, quindi il compito di incorporarli nel progetto ricadrà interamente sullo sviluppatore.
Esistono diversi strumenti per raggiungere scopi diversi. Ad esempio, ci sono strumenti di compilazione per eseguire attività per la compressione e il ridimensionamento delle immagini, la minimizzazione di file JS e CSS e la copia di file in una directory per la produzione di una versione, come Webpack, Grunt e Gulp; altri strumenti aiutano a creare l'impalcatura di un progetto, utile per produrre la struttura delle cartelle per i nostri temi o plugin, come Yeoman. In effetti, con così tanti strumenti in giro, sfogliare articoli confrontando i diversi strumenti disponibili ci aiuterà a trovare quello più adatto alle nostre esigenze.
In alcuni casi, tuttavia, non esistono strumenti di compilazione in grado di ottenere esattamente ciò di cui ha bisogno il nostro progetto, quindi potrebbe essere necessario codificare il nostro strumento di compilazione come estensione del progetto stesso. Ad esempio, l'ho fatto per generare il file service-worker.js per aggiungere il supporto per Service Workers in WordPress.
Conclusione
A causa della sua forte enfasi sul mantenimento della retrocompatibilità, estesa anche fino a PHP 5.2.4, WordPress non ha potuto beneficiare delle ultime funzionalità aggiunte a PHP, e questo fatto ha reso WordPress una piattaforma poco entusiasmante per programmare per molti sviluppatori.
Fortunatamente, questi giorni uggiosi potrebbero presto finire e WordPress potrebbe tornare a essere una piattaforma brillante ed eccitante per cui programmare ancora una volta: il requisito di PHP 7.0+ a partire da dicembre 2019 renderà disponibili molte funzionalità PHP, consentendo agli sviluppatori di produrre più potenti e software più performante. In questo articolo, abbiamo esaminato le più importanti funzionalità PHP appena disponibili e come sfruttarle al meglio.
Il recente rilascio di Gutenberg potrebbe essere un segno dei bei tempi a venire: anche se Gutenberg stesso non è stato pienamente accettato dalla community, almeno dimostra la volontà di incorporare le ultime tecnologie (come React e Webpack) nel core . Questa svolta degli eventi mi fa chiedere: se il frontend può ottenere un tale restyling, perché non estenderlo al backend? Una volta che WordPress richiede almeno PHP 7.0, l'aggiornamento a strumenti e metodologie moderne può accelerare: per quanto npm sia diventato il gestore di pacchetti JavaScript preferito, perché non rendere Composer il gestore delle dipendenze PHP ufficiale? Se i blocchi sono la nuova unità per i cantieri nel frontend, perché non utilizzare i componenti PHP come unità per incorporare le funzionalità nel backend? E infine, se Gutenberg tratta WordPress come un CMS back-end sostituibile, perché non riconoscere già che WordPress è una dipendenza dal sito e non dal sito stesso? Lascerò queste domande aperte su cui riflettere e su cui riflettere.