Parte 2 – WordPress e programmazione orientata agli oggetti: un esempio del mondo reale

Pubblicato: 2021-07-29

Nella nostra Panoramica di WordPress e della programmazione orientata agli oggetti abbiamo esaminato la teoria alla base della programmazione orientata agli oggetti (OOP) e cosa aspettarci quando la si utilizza.

Prima di procedere con esempi di codifica più specifici utilizzando l'OOP, in questo articolo cercheremo di spiegare come si può affrontare uno scenario del mondo reale con la diversa mentalità richiesta per l'OOP e come questo viene analizzato utilizzando oggetti e classi.

Uno scenario di vita reale: invio di un SMS

Questo è più simile a uno scenario di vita "passato" in realtà poiché gli SMS vengono utilizzati sempre meno al giorno d'oggi, ma come vedrai, c'è un motivo per cui lo usiamo come esempio!

Supponiamo che tu abbia un dispositivo mobile e desideri inviare un messaggio di testo a uno dei tuoi contatti. Mantenendo l'esempio il più semplice possibile, la sequenza di azioni sarebbe:

  1. Prepara il messaggio
  2. Seleziona uno dei tuoi contatti e aggiungilo come destinatario
  3. Invia il messaggio

Quindi proviamo a visualizzare i passaggi che seguiresti per inviare il tuo messaggio:

Abbiamo aggiunto alcune descrizioni più dettagliate delle azioni ma più o meno tutto ciò che fai sono 3 passaggi di base. Si prepara il messaggio nell'editor del dispositivo, si seleziona il destinatario dai contatti e quindi si invia il messaggio. E hai finito! Il tuo messaggio è ora inviato.

Ora, se dovessimo rappresentare in codice un'applicazione che invia un messaggio SMS, dovremmo analizzare quale percorso è meglio seguire; l'approccio procedurale o OOP.

La domanda con un approccio procedurale

Se sei uno sviluppatore di plugin per WordPress, molto probabilmente hai familiarità con la programmazione procedurale .

Come abbiamo descritto in precedenza, la programmazione procedurale è un tipo di programmazione imperativa, in cui i nostri programmi sono costituiti da una o più procedure. Quindi, come sviluppatore, scomponi il tuo plug-in in un gruppo di variabili che contengono i tuoi dati e funzioni che operano sui dati.

Nel nostro esempio sopra con il messaggio SMS, eseguiresti una serie di azioni che porterebbero al risultato desiderato. Come avrai già intuito, avresti, ad esempio, una variabile che contiene il contenuto del testo del messaggio, una funzione con un parametro $contact che restituisce il numero di telefono e, infine, una funzione che invia il messaggio. In codice sarebbe simile a questo:

 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 lo useresti così:

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

Quindi, completeresti una serie di attività che ti porteranno al risultato desiderato.

In questo esempio molto semplice, ovviamente, che ha requisiti limitati e molto specifici, non c'è alcun motivo per considerare l'utilizzo di OOP. La programmazione procedurale è più che sufficiente per raggiungere il tuo obiettivo. Ma, se pensi ad alcuni scenari su come questa applicazione potrebbe espandersi in futuro, potresti renderti conto che, a lungo termine, potresti avere problemi in termini di scalabilità. Cercheremo di spiegare perché di seguito.

Ampliare l'applicazione con l'approccio procedurale

Supponiamo che tu voglia migliorare questa applicazione e fornire la possibilità di inviare anche altri tipi di messaggi, come ad esempio un'e-mail. La funzione che consegna il messaggio sarebbe diversa in ogni caso.

Quando si invia un'e-mail, è necessario l'indirizzo e-mail del contatto, non il numero di telefono. A parte questo, dovremo aggiungere un parametro nella funzione finale send_message() che corrisponda al tipo di tecnologia che utilizziamo; e-mail o SMS.

Il codice corrispondente potrebbe assomigliare a questo:

 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 ); } }

Quindi, non è che questo non possa essere implementato con un approccio procedurale. Ma se sei uno sviluppatore esperto probabilmente hai già capito come questo potrebbe diventare disordinato in futuro.

Gli svantaggi con un approccio procedurale

E se avessimo più tipi di messaggi? Le istruzioni if ​​diventerebbero fastidiosamente grandi. E, soprattutto, cosa succederebbe se avessi funzioni che utilizzano la funzione send_message() ? In tal caso, dovresti aggiungere anche il parametro $technology in tutte quelle funzioni.

Man mano che il tuo codice cresce, le funzioni saranno ovunque, il che significa che inizierai a copiare/incollare blocchi di codice (mai desiderabile) e apportare una piccola modifica a una funzione potrebbe interrompere molte altre funzioni. Ci siamo stati tutti. Vorresti evitarlo ed essere in grado di aggiungere facilmente funzionalità al tuo codice senza interferire troppo nella struttura.

Ospita il tuo sito web con Pressidium

GARANZIA DI RIMBORSO DI 60 GIORNI

GUARDA I NOSTRI PIANI

La programmazione orientata agli oggetti (o OOP) è un paradigma di programmazione che tenta di risolvere questo problema consentendoci di strutturare il nostro plug-in in piccoli pezzi di codice riutilizzabili, chiamati classi . Come abbiamo descritto nel nostro articolo Panoramica OOP, una classe è fondamentalmente un modello che usiamo per creare singole istanze della classe, chiamato objects .

Un oggetto contiene dati e codice. Abbiamo ancora variabili in grado di memorizzare informazioni, chiamate proprietà . E procedure che operano sui dati, chiamate metodi .

L'applicazione con un approccio OOP

Ora analizziamo lo stesso scenario di cui sopra con un approccio OOP.

In primo luogo, definiremo quali oggetti abbiamo qui, quali caratteristiche ha ciascuno e quali azioni svolgono. Le caratteristiche sono quelle che in seguito saranno le nostre proprietà e le azioni saranno le nostre funzioni o metodi come vengono chiamati in OOP.

Pensiamo a cosa abbiamo nel primo scenario di invio di un SMS nel modo più semplice possibile. C'è un dispositivo che ha un'interfaccia che usiamo per inviare il messaggio SMS. Abbiamo il contenuto del messaggio, scegliamo un contatto come destinatario e infine il messaggio.

 <?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 ); }

Dichiariamo la classe Phone che implementa l'interfaccia MessagingCapable . Quindi dobbiamo implementare tutti i metodi dichiarati in esso. La funzione say_hi() richiede 3 parametri:

  1. Un dispositivo che supporta la messaggistica
  2. Un contatto
  3. Il messaggio

Per inviare effettivamente un messaggio utilizziamo questa funzione in questo modo:

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

Fondamentalmente stiamo creando un oggetto istanziando la classe Phone e passando il contatto e il contenuto del messaggio. Ciò produrrebbe:

 You sent "Hello John"

Abbiamo dimostrato questo semplice scenario di invio di un messaggio di testo utilizzando le classi. Nella prossima sezione, vedremo come espandere le capacità dell'applicazione seguendo l'approccio OOP e, durante l'espansione, esamineremo il ruolo svolto dalle funzionalità OOP e i vantaggi dell'utilizzo di questa tecnica.

Espandere l'applicazione con l'approccio OOP

Aggiungiamo anche la possibilità di inviare e-mail, come abbiamo fatto prima in modo procedurale.

Indipendentemente dal dispositivo, idealmente vorremmo utilizzare la funzione say_hi() allo stesso modo. Dai un'occhiata al codice qui sotto:

 <?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 utilizziamo questo pezzo di codice, prendiamo il dispositivo mobile per inviare un SMS e il computer per inviare un'e-mail. Vorremmo:

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

o:

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

che risulterebbe You sent a "Hello John" SMS to John Doe e You sent a "Hello John" email to John Doe corrispondentemente.

Qui iniziamo già a rilevare alcune funzionalità OOP. Abbiamo introdotto le interfacce utilizzando l'interfaccia MessagingCapable .

Un'interfaccia dichiara un insieme di metodi che devono essere implementati dalla classe senza definire come questi metodi vengono implementati. Tutti i metodi dichiarati in un'interfaccia devono essere pubblici.

PHP non supporta l'ereditarietà multipla, il che significa che una classe non può ereditare le proprietà/metodi di più classi padre.

Sebbene possa estendere solo una classe, può implementare più interfacce.

L'utilizzo di un telefono per inviare un messaggio sarà diverso dall'utilizzo di un computer. Istanze di classi diverse agiscono in modo diverso quando viene chiesto di eseguire la stessa azione (ad esempio send_message() ). Questo è un esempio di polimorfismo. Se in seguito creiamo un nuovo dispositivo, non avremo bisogno di modificare il nostro codice per adattarlo, purché condividano tutti la stessa interfaccia.

Vorremmo anche sottolineare qui che vediamo già la differenza anche nella leggibilità. Il modo in cui finalmente utilizziamo questo script semplicemente codificando:

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

Questo è totalmente semplice per qualsiasi sviluppatore che lavora al progetto. E, naturalmente, più complesso è il plug-in, diventa più ovvio quanto sia utile, soprattutto quando si lavora in team.

Per cercare di spiegare meglio quanto sia facile espandere il tuo plug-in in Programmazione orientata agli oggetti, proviamo ad aggiungere alcune funzionalità in più.

Aggiunta di più funzionalità

Se vogliamo aggiungere la possibilità di navigare in Internet, aggiungeremo semplicemente un'interfaccia aggiuntiva per qualsiasi dispositivo in grado di rispondere a questa capacità, come ad esempio un computer.

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

L'implementazione di questa interfaccia sarà codificata in questo modo:

 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 ); } }

Quindi nella classe Computer corrente abbiamo appena aggiunto l'interfaccia extra da implementare, poiché un computer può inviare un messaggio e navigare in Internet, e il visit_website( $url ) .

NOTA: Naturalmente, poiché visitare un URL è totalmente irrilevante con la funzione say_hi() , introdurremo anche una nuova funzione, qualcosa del tipo:

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

E questo è tutto! Per qualsiasi dispositivo che può visitare un URL possiamo utilizzare questa funzione come abbiamo fatto con il computer. Non ci sono preoccupazioni che interromperai il resto della funzionalità. Questo mostra la scalabilità disponibile quando si utilizza OOP rispetto alla programmazione procedurale.

Aggiungiamo un dispositivo smartphone solo per dimostrare alcune funzionalità in più. Ecco tutto il codice, con l'aggiunta della classe smartphone in modo da avere un quadro migliore di quello che sta succedendo:

 <?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 ); }

La classe Smartphone estende la classe padre Phone e implementa l'interfaccia InternetBrowsingCapable . Ciò significa che può inviare un messaggio e visitare un URL. Qui, rileviamo la funzione Ereditarietà. In altre parole, abbiamo una gerarchia di classi, una classe genitore (telefono) e una sottoclasse (smartphone).

Quindi un oggetto Smartphone eredita tutte le proprietà e i comportamenti della classe Phone madre. In questo modo, all'interno della classe figlia possiamo aggiungere un metodo o sovrascrivere un metodo della classe genitore, come abbiamo fatto con send_message() nella classe Smartphone. L'abbiamo fatto per modificare l'output. Potremmo ignorare completamente questo metodo e utilizzare send_message() della classe genitore così com'è.

Puoi provare tu stesso il codice incollandolo nel blocco di codice di questo fantastico strumento online PHP. Sotto il codice, prova una di queste righe di codice e osserva i diversi risultati.

 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" );

Per una comprensione ancora migliore dell'intero concetto, dai un'occhiata al diagramma Class del codice sopra.

Come illustrato sopra, quando si progettano le relazioni tra classi, non includiamo gli elementi comuni nella classe figlia. Inoltre, non dimenticare di prestare attenzione nella guida a sinistra in modo da poter identificare le relazioni e la visibilità delle loro proprietà e modalità.

Se desideri vedere anche la funzione Encapsulation in azione, prova a includere una classe Contact in uno qualsiasi degli script di esempio sopra forniti. La classe sarebbe simile a questa:

 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; } }

Il metodo __construct() , in base alla progettazione, viene chiamato automaticamente alla creazione di un oggetto. Ora, quando istanziamo la classe Contact, il suo costruttore viene chiamato e imposta i valori delle sue proprietà private. Quindi utilizziamo i nostri "getter" che sono i metodi pubblici get_name() , get_phone_number() e get_email_address() per recuperare questi valori.

L'incapsulamento raggruppa i dati con i metodi che operano sui dati limitando l'accesso diretto impedendo l'esposizione di dettagli di implementazione nascosti.

Conclusione

Si spera che questo articolo ti abbia aiutato a comprendere la programmazione orientata agli oggetti in un modo più pratico. OOP aiuta davvero a rendere più facile l'espansione dell'applicazione in futuro, se necessario, essendo chiara e riutilizzabile.

Inoltre, un plug-in che utilizza OOP sarà più veloce e facile da eseguire. Questo perché i metodi comuni a tutti gli oggetti di una classe consumano memoria solo una volta, durante la loro dichiarazione.

Anche la sicurezza è migliorata grazie all'incapsulamento. Nella programmazione procedurale, invece, tutti i dati sono globali, il che significa che l'accesso è disponibile da qualsiasi luogo.

Come risultato di quanto sopra, anche la manutenzione del codice, la produttività, la scalabilità e la risoluzione dei problemi diventano molto più semplici per te e il tuo team.

Nei prossimi articoli di questa serie vedremo in azione questo stile di programmazione applicandolo a un plugin di WordPress. Nello specifico, creeremo una copia del plugin Limit Login Attempts versione 1.7.1 creato da Johan Eenfeldt ma convertito il più possibile con un approccio Object-Oriented.

Durante questo processo, analizzeremo il flusso del plug-in e imposteremo i requisiti. Andando avanti, proveremo le nostre prime riflessioni sulla progettazione del plugin e, nella fase di implementazione, scriveremo il codice. Durante il processo di implementazione faremo avanti e indietro e riprogetteremo, se necessario, per ottenere i risultati desiderati.

Tuttavia, non entreremo nei dettagli su tutte le parti del codice. Invece, vorremmo concentrarci sulla condivisione del modo in cui i plugin sono costruiti in modo orientato agli oggetti. Siamo fiduciosi che, una volta che avrai finito di leggere questa serie di articoli, potrai creare benissimo un tuo plugin OOP.

Fare clic qui per leggere la parte 3 della nostra serie di programmazione orientata agli oggetti

Guarda anche

  • WordPress e programmazione orientata agli oggetti: una panoramica