Un'introduzione ai modelli di progettazione in PHP (e sfruttarli in Drupal)
Pubblicato: 2022-07-05Qualcuno intelligente una volta ha detto: buon codice di codifica, ottimo riutilizzo.
Gli sviluppatori spesso si trovano a risolvere ripetutamente lo stesso tipo di problemi. Il riutilizzo del codice è davvero il Santo Graal dello sviluppo software. Inoltre, a chi non piace leggere (e scrivere) codice ben strutturato? Invio - modelli di progettazione in PHP.
I pattern di progettazione PHP si sono rivelati estremamente utili per gli sviluppatori e sono un grande risolutore di problemi. Seguire le migliori pratiche è fondamentale per scrivere codice efficiente. PHP Design patterns è un concetto di programmazione orientata agli oggetti (OOP) che ora viene utilizzato anche nei progetti Drupal 9. Con l'adozione da parte di Drupal dei moderni concetti PHP e OOP dalla versione 8, i modelli di progettazione possono essere sfruttati per una programmazione più pulita e robusta. In questo articolo, discuteremo alcuni modelli di progettazione comunemente usati in PHP e come utilizzare modelli come le iniezioni di dipendenze in Drupal.
Ancora su Drupal 7? Leggi questo articolo per trovare un pratico elenco di controllo che ti aiuterà a prepararti per una migrazione a Drupal 9.

Cosa sono i Design Pattern in PHP?
Nell'ingegneria del software, un Design Pattern è una soluzione generale ripetibile a problemi che si verificano comunemente nella progettazione del software. I buoni progetti orientati agli oggetti dovrebbero essere riutilizzabili, manutenibili ed estensibili e i modelli di progettazione in PHP potrebbero essere molto utili a tal fine. Non solo aiuta a risolvere i problemi, ma implica un modo ottimale per affrontare le sfide comuni.
Perché usare i modelli di progettazione PHP
Alcuni dei vantaggi più significativi dell'implementazione di modelli di progettazione in PHP sono:
- I modelli di progettazione PHP aiutano a risolvere i problemi ripetitivi affrontati durante lo sviluppo
- L'utilizzo di modelli di progettazione in PHP rende più efficiente la comunicazione tra designer e sviluppatori
- Puoi essere certo che altri sviluppatori capiranno il tuo codice poiché segue modelli di progettazione
- Seguire le best practice aiuta a creare applicazioni più robuste
- Aiuta a rendere lo sviluppo più veloce e più facile
Modelli di progettazione ampiamente utilizzati in PHP
I modelli di progettazione possono essere utilizzati in varie situazioni per risolvere problemi simili. Esistono più di 30 modelli di progettazione che possono essere classificati in tre tipi: modelli creativi, strutturali e comportamentali.
Modelli di creazione: modelli di progettazione utilizzati nei meccanismi di creazione di oggetti, per creare oggetti che possono essere disaccoppiati dal sistema che li ha implementati.
Motivi strutturali: questo facilita il design identificando modi semplici per realizzare relazioni tra entità
Modelli comportamentali: vengono utilizzati per gestire relazioni, responsabilità e algoritmi tra oggetti
Modello di fabbrica
Un modello di fabbrica viene utilizzato per costruire un oggetto. Esatto: costruisci un oggetto e non crea un oggetto. Quando costruiamo l'oggetto, lo creiamo prima e poi lo inizializziamo. Di solito, richiede l'applicazione di una certa logica ed eseguire più passaggi. Con ciò, ha senso avere tutto ciò in un unico posto e riutilizzarlo ogni volta che è necessario costruire un nuovo oggetto nello stesso modo. Fondamentalmente, questo è l'uso del modello di fabbrica.
È un'ottima idea avere un'interfaccia per la nostra fabbrica e fare in modo che il nostro codice dipenda da essa e non da una fabbrica concreta.
interface FamilyFactoryInterface { public function create() : Family }Quindi, implementa l'interfaccia di fabbrica con la classe seguente:
class FamilyFactory implements FamilyFactoryInterface { public function create() : Family { $family = new Family(); // initialize your family return $family; } }Modello adattatore
In Adapter Design Pattern, una classe trasforma l'interfaccia di una classe in un'altra classe. In questo esempio abbiamo una classe TextBook che ha i metodi getTitle() e getAuthor(). Il client si aspetta un metodo getTitleAndAuthor(). Per "adattare" SimpleBook per demoAdapter abbiamo una classe adattatore, BookAdapter , che accetta un'istanza di TextBook e utilizza i metodi TextBook getTitle() e getAuthor() nel proprio metodo getTitleAndAuthor.
<?php class TextBook { private $title; private $author; function __construct($title_in, $author_in) { $this->title = $title_in; $this->author = $author_in; } function getTitle() { return $this->title; } function getAuthor() { return $this->author; } } class BookAdapter { private $book; function __construct(TextBook $book_in) { $this->book = $book_in; } function getTitleAndAuthors() { return $this->book->getTitle().' by '.$this->book->getAuthor(); } } // client writeln('BEGIN TESTING ADAPTER PATTERN'); writeln(''); $book = new TextBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns"); $bookAdapter = new BookAdapter($book); writeln('Author and Title: '.$bookAdapter->getTitleAndAuthor()); writeln(''); writeln('END TESTING ADAPTER PATTERN'); function writeln($line_in) { echo $line_in."<br/>"; } ?>Modello singleton PHP
Per limitare l'istanziazione di una classe a un singolo oggetto, viene utilizzato un pattern singleton in PHP. Questo può essere utile quando è necessario un solo oggetto nel sistema. Ha senso consentire l'accesso a una sola istanza di una determinata classe durante la progettazione di applicazioni Web. Per impedire la creazione esplicita di oggetti dalla classe del modello Singleton, viene utilizzato un costruttore privato.
<?php class Singleton { public static function getInstance() { static $instance = null; if (null === $instance) { $instance = new static(); } return $instance; } protected function __construct() { } private function __clone() { } private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); $obj2 = SingletonChild::getInstance(); var_dump($obj2 === Singleton::getInstance()); var_dump($obj2 === SingletonChild::getInstance()); ?>Schema dell'osservatore in PHP
Il pattern PHP Observer viene utilizzato per avvisare il resto del sistema di eventi particolari in determinati luoghi.
Ad esempio, se dobbiamo creare un teatro per mostrare i film alla critica. Definiamo la classe Teatro con il metodo attuale. Prima di presentare il film, vogliamo inviare messaggi ai cellulari dei critici. Poi, a metà del film, vogliamo fermare il film per 5 minuti per lasciare che i critici abbiano un intervallo. Infine, dopo la fine del film, vogliamo chiedere alla critica di lasciare la propria risposta. Quindi, nel modello osservatore per PHP, l'oggetto osservatore riceve una notifica solo quando lo stato viene modificato.

Ecco come appare il codice -
class Theater { public function current(Movie $movie) : void { $critics = $movie->getCritics(); $this->message->send($critics, '...'); $movie->play(); $movie->pause(5); $this->progress->interval($critics) $movie->end(); $this->response->request($critics); } }Motivo decorativo per PHP
Il modello Decorator viene utilizzato quando si desidera modificare il carattere di un oggetto in fase di esecuzione e, di conseguenza, ridurre le eredità non necessarie e il numero di classi. Bene, può essere spiegato con esempi. Diciamo che abbiamo classi Sofa e Bed, ed entrambe implementano SleeperInterface.
interface SleeprInterface { public function sleep() : void; } class Sofa implements SleeperInterface { public function sleep() : void { // sleeps on sofa } } class Bed implements SleeperInterface { public function sleep() : void { // sleeps on bed } }Sia i divani che i letti hanno lo stesso comportamento per dormire. Ora, abbiamo bisogno di altri divani e letti con funzionalità aggiuntive che indichino agli utenti il monitoraggio del sonno quando dormono sui divani o sui letti. Con l'ereditarietà possiamo risolvere questo problema proprio in questo modo:
class SmartSofa extends Sofa { public function sleep() : void { parent::sleep(); $this->sleepHours(); } } class SmartBed extends Window { public function sleep() : void { parent::sleep(); $this->sleepHours(); } }
Ora abbiamo 4 classi in totale. Tuttavia, potremmo risolvere questo problema con 3 classi solo con il pattern Decorator. Ecco come:
class SmartSleeper implements SleeperInterface { private $sleeper; public function __construct(SleeperInterface $sleeper) { $this->sleeper = $sleeper; } public function sleep() : void { $this->sleeper->sleep(); $this->sleepHours(); } } $sofa = new Sofa(); $bed = new Bed(); $smartSofa = new SmartSleeper($sofa); $smartBed = new SmartSleeper($bed);Qui, abbiamo introdotto un nuovo tipo di dormiente che agisce come un proxy ma con una funzionalità extra.
Sfruttare i modelli di progettazione in Drupal 9
Sebbene ci siano molti modelli di progettazione già stabiliti in Drupal prima di Drupal 9, ora ci sono molti altri modelli che in precedenza non erano disponibili. Alcuni di questi nuovi modelli sostituiscono completamente quelli precedenti, mentre altri introducono alcune nuove funzionalità in Drupal 9.
I modelli di progettazione utilizzati in Drupal 9 includono:
- Pattern di programmazione orientato agli oggetti (OOP)
- Iniezioni di dipendenza
- Modello di fabbrica
- Modello singleton
L'OOP non è in realtà un modello singolo, ma un modo completamente radicale di concettualizzare e strutturare il codice che va ben oltre i semplici modelli di progettazione. È la base per molti modelli di progettazione software popolari in uso oggi, inclusi quelli utilizzati in Drupal 9. È stato introdotto in Drupal 7, ma non è stato ampiamente utilizzato e non era richiesto. La situazione in Drupal 9 è ora diversa, è ampiamente utilizzato ed è necessario.
Iniezioni di dipendenza
L'iniezione delle dipendenze è un modello di progettazione del software che consente di rimuovere le dipendenze codificate e anche di modificarle in fase di esecuzione o in fase di compilazione. L'aggiunta dell'iniezione delle dipendenze è facile e non interferisce con il codice esistente. Drupal 8 ha introdotto il concetto di servizi per disaccoppiare le funzionalità riutilizzabili. core.services.yml è un esempio di iniezione di dipendenza in Drupal 9. Abbiamo già discusso di Factory Pattern e Singleton Pattern in PHP in precedenza.
Attualmente, in Drupal, l'inserimento delle dipendenze è il metodo preferito per accedere e utilizzare i servizi e dovrebbe essere utilizzato quando possibile. Invece di chiamare il contenitore dei servizi globali, i servizi vengono piuttosto passati come argomenti a un costruttore o iniettati tramite metodi setter. Il passaggio esplicito dei servizi da cui dipende un oggetto viene chiamato iniezione di dipendenza . In molti casi, le dipendenze vengono passate in modo esplicito nei costruttori di classi.
Dai un'occhiata a questa pagina per trovare tutti i servizi disponibili in Drupal core. Puoi leggere di più sui servizi nella documentazione di Drupal.
Consideriamo il servizio 'entity_type.manager' come esempio per ottenere il titolo per il nodo con ID=1. Per inserirlo nel nostro servizio personalizzato, dobbiamo solo prendere il nome del servizio e passarlo come argomento nel file my_module_name.services.yml come mostrato di seguito:
mio_nome_modulo.servizi.yml
services: my_module_name.helper: class: Drupal\my_module_name\MyModuleHelper arguments: ['@entity_type.manager']e quindi nella nostra classe di servizio non ci resta che ottenere il servizio nel metodo _ _construct e memorizzarlo in una variabile come questa:
MyModuleHelper.php
<?php namespace Drupal\my_module_name; use Drupal\Core\Entity\EntityTypeManagerInterface; /** * MyModuleHelper is a simple example of a Drupal 9 service. */ class MyModuleHelper { /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * Part of the DependencyInjection magic happening here. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. */ public function __construct(EntityTypeManagerInterface $entity_type_manager) { $this->entityTypeManager = $entity_type_manager; } /** * Returns a title for node_id = 1. */ public function getFirstNodeTitle() { $node = $this->entityTypeManager->getStorage('node')->load(1); return $node->getTitle(); } }e quindi potremmo usare il servizio di gestione del tipo di entità e ottenere il titolo del nodo con nid=1 nel metodo getFirstNodeTitle.
Grazie mille ad Ankitha Shetty per le sue intuizioni che ci hanno aiutato ad aggiornare l'articolo.
