SmartObject
SmartObject ha migliorato per anni il comportamento degli oggetti in PHP. Dalla versione PHP 8.4, tutte le sue funzionalità sono diventate parte nativa di PHP stesso, completando così la sua missione storica di essere pioniere dell'approccio orientato agli oggetti moderno in PHP.
Installazione:
SmartObject è nato nel 2007 come soluzione rivoluzionaria alle carenze del modello a oggetti di PHP dell'epoca. In un periodo in cui PHP soffriva di numerosi problemi di design orientato agli oggetti, ha portato significativi miglioramenti e semplificazioni nel lavoro degli sviluppatori. È diventato una parte leggendaria del framework Nette. Ha offerto funzionalità che PHP avrebbe acquisito solo molti anni dopo – dalla validazione dell'accesso alle proprietà alla gestione sofisticata degli errori. Con l'arrivo di PHP 8.4, ha completato la sua missione storica, poiché tutte le sue funzionalità sono diventate parti native del linguaggio. Ha anticipato lo sviluppo di PHP di ben 17 anni.
SmartObject ha attraversato un'interessante evoluzione tecnica. Inizialmente, è stato implementato come classe
Nette\Object
, dalla quale altre classi ereditavano la funzionalità necessaria. Un cambiamento significativo è
arrivato con PHP 5.4, che ha introdotto il supporto per i trait. Questo ha permesso la trasformazione nel trait
Nette\SmartObject
, portando maggiore flessibilità – gli sviluppatori potevano utilizzare la funzionalità anche
nelle classi che già ereditavano da un'altra classe. Mentre la classe originale Nette\Object
ha cessato di esistere
con PHP 7.2 (che ha proibito di nominare le classi con la parola ‚Object‘), il trait Nette\SmartObject
continua a
esistere.
Esaminiamo le funzionalità che Nette\Object
e successivamente Nette\SmartObject
offrivano. Ognuna di
queste funzioni rappresentava un significativo passo avanti nella programmazione orientata agli oggetti in PHP.
Stati di Errore Consistenti
Uno dei problemi più urgenti del primo PHP era il comportamento inconsistente nel lavoro con gli oggetti.
Nette\Object
ha portato ordine e prevedibilità in questo caos. Vediamo come si comportava PHP originariamente:
Fatal error terminava l'applicazione senza possibilità di reazione. La scrittura silenziosa su membri non esistenti senza
avviso poteva portare a errori gravi difficili da rilevare. Nette\Object
catturava tutti questi casi e lanciava una
MemberAccessException
, permettendo ai programmatori di reagire e gestire questi errori:
Da PHP 7.0, il linguaggio non causa più errori fatali non catturabili e da PHP 8.2, l'accesso a membri non dichiarati è considerato un errore.
Suggerimento „Did you mean?“
Nette\Object
è arrivato con una funzionalità molto conveniente: i suggerimenti intelligenti per gli errori di
battitura. Quando uno sviluppatore commetteva un errore nel nome di un metodo o di una variabile, non solo segnalava l'errore ma
offriva anche aiuto suggerendo il nome corretto. Questo messaggio iconico, noto come „did you mean?“, ha risparmiato agli
sviluppatori ore di ricerca degli errori di battitura:
Mentre PHP stesso non ha alcuna forma di „did you mean?“, questa funzionalità è ora fornita da Tracy. Può persino correggere automaticamente questi errori.
Proprietà con Accesso Controllato
Un'innovazione significativa che SmartObject ha portato in PHP sono state le proprietà con accesso controllato. Questo concetto, comune in linguaggi come C# o Python, ha permesso agli sviluppatori di controllare elegantemente l'accesso ai dati dell'oggetto e garantire la loro consistenza. Le proprietà sono uno strumento potente della programmazione orientata agli oggetti. Funzionano come variabili ma sono in realtà rappresentate da metodi (getter e setter). Questo permette la validazione degli input o la generazione dei valori al momento della lettura.
Per utilizzare le proprietà, è necessario:
- Aggiungere l'annotazione
@property <type> $xyz
alla classe - Creare un getter chiamato
getXyz()
oisXyz()
, un setter chiamatosetXyz()
- Assicurarsi che getter e setter siano public o protected. Sono opzionali – quindi possono esistere come proprietà read-only o write-only
Vediamo un esempio pratico usando la classe Circle, dove useremo le proprietà per garantire che il raggio sia sempre non
negativo. Sostituiremo public $radius
con una proprietà:
Da PHP 8.4, la stessa funzionalità può essere ottenuta usando i property hooks, che offrono una sintassi molto più elegante e concisa:
Extension Methods
Nette\Object
ha portato in PHP un altro concetto interessante ispirato ai linguaggi di programmazione moderni –
i metodi di estensione. Questa funzionalità, presa in prestito da C#, permetteva agli sviluppatori di estendere elegantemente le
classi esistenti con nuovi metodi senza modificarle o ereditare da esse. Per esempio, si poteva aggiungere un metodo
addDateTime()
a un form che aggiungesse un DateTimePicker personalizzato:
I metodi di estensione si sono rivelati poco pratici perché gli editor non suggerivano i loro nomi e invece segnalavano che il metodo non esisteva. Pertanto, il loro supporto è stato interrotto. Oggi, è più comune utilizzare la composizione o l'ereditarietà per estendere la funzionalità delle classi.
Ottenere il Nome della Classe
SmartObject offriva un metodo semplice per ottenere il nome della classe:
Accesso a Reflection e Annotazioni
Nette\Object
forniva accesso a reflection e annotazioni attraverso i metodi getReflection()
e
getAnnotation()
. Questo approccio semplificava significativamente il lavoro con le meta-informazioni delle
classi:
Da PHP 8.0, è possibile accedere alle meta-informazioni attraverso gli attributi, che offrono ancora più possibilità e un migliore controllo dei tipi:
Method Getters
Nette\Object
offriva un modo elegante per passare i metodi come se fossero variabili:
Da PHP 8.1, è possibile utilizzare la first-class callable syntax, che porta questo concetto ancora più avanti:
Eventi
SmartObject offre una sintassi semplificata per lavorare con gli eventi. Gli eventi permettono agli oggetti di informare altre parti dell'applicazione sui cambiamenti del loro stato:
Il codice $this->onChange($this, $radius)
è equivalente al seguente ciclo:
Per chiarezza, raccomandiamo di evitare il metodo magico $this->onChange()
. Un'alternativa pratica è la
funzione Nette\Utils\Arrays::invoke: