I blog di Alessioempoli

Data 7 ottobre 2018

Programmazione a oggetti con PHP – 3

Per ingrandire il testo, cliccare sul browser

Per ingrandire le foto, cliccarci sopra

          Programmazione a oggetti con PHP – 3

 

 

Proprietà statiche

 

Le proprietà che sono componenti statiche della stessa classe

 

Nella lezione dedicata alle costanti, abbiamo dato uno sguardo alla differenza che si interpone tra dati dinamici e dati statici di una classe. Come abbiamo già visto, è possibile classificare le proprietà ed i metodi come dati dinamici e le costanti come dati statici.

Tuttavia, oltre a queste, esistono altre componenti che è possibile dichiarare in una classe: le proprietà statiche ed i metodi statici.

 

Le proprietà statiche

 

A differenza delle normali proprietà, che appartengono alle determinate istanze della classe e vengono richiamate con l’operatore di deferenziamento (“->”) e che rappresentano dunque dei dati istanza, le proprietà statiche non appartengono a nessuna istanza in particolare, ma sono di fatto componenti statiche di proprietà della classe stessa.

Ciò significa che non è possibile richiamare le proprietà statiche attraverso le istanze, ma occorre, come nel caso delle costanti, usare l’operatore di risoluzione dell’ambito (“::”) oppure la keyword self.

Le proprietà statiche si dichiarano attraverso la parola chiave static, preceduta o seguita opzionalmente dall’indicatore di visibilità (che analizzeremo nelle successive lezioni) e dal namespace desiderato. Se non si specifica nessun indicatore di visibilità, verrà utilizzato il valore public. Ecco un esempio di dichiarazione ed utilizzo delle proprietà statiche:

 

1-

 

Come possiamo notare, a differenza delle costanti che non richiedono il simbolo del dollaro “$” iniziale, con le proprietà statiche occorre dichiararlo. Le proprietà statiche dunque, essendo dati statici, non possono essere richiamate attraverso le istanze della classe, altrimenti PHP cercherà una proprietà normale avente lo stesso nome e concluderà con l’errore E_NOTICE Undefined property…:

 

2-

 

Ma cosa cambia dunque, tra le proprietà statiche e le costanti, a parte la differente sintassi?

La risposta è molto semplice: mentre le costanti sono dati immutabili, cioè che devono rimanere invariati durante il corso di tutta l’applicazione, le proprietà statiche possono cambiare il loro valore come le normali proprietà. Ecco un esempio in cui, tramite il metodo costruttore, si contano quante istanze vengono create nel corso del nostro script e tramite il metodo distruttore viene indicato quale istanza, identificata da un idKey univoco, è stata eliminata:

 

3-

 

 

I metodi statici

 

I metodi che vengono dichiarati a livello di classe e non a livello di istanza

 

I metodi statici stanno esattamente ai metodi non-statici come le proprietà statiche statiche stanno alle proprietà non-statiche. Ciò significa che anche i metodi statici sono dati di classe che non appartengono a nessuna istanza in particolare. Anch’essi devono essere preceduti dalla keyword static:

 

4-

 

Ovviamente, dato che i metodi statici non sono legati alle istanze, non è possibile utilizzare la pseudo variabile $this al proprio interno. Tuttavia, anche se è una pratica davvero sconsigliata, è comunque possibile richiamare i metodi statici tramite le istanze senza causare errori fatali, cosa che non è assolutamente fattibile nel caso delle proprietà statiche:

 

5-

 

Dati dinamici e dati statici: gli operatori

Ora che abbiamo analizzato nel dettaglio tutte le componenti dinamiche e statiche che è possibile dichiarare all’interno di una classe, riassumiamo l’uso dei vari operatori che è necessario usare in collaborazione con questi elementi:

 

# con i dati dinamici (proprietà e metodi) occorre utilizzare la pseudo variabile $this per riferirsi agli elementi dall’interno della classe, mentre si deve utilizzare il namespace dell’istanza per riferirsi dall’esterno. L’operatore da utilizzare in entrambi i casi è l’operatore di deferenziamento (“->”)

# con i dati statici (costanti, proprietà statiche e metodi statici) occorre utilizzare l’operatore di risoluzione dell’ambito (“::”) unito al nome della classe che li contiene oppure alla keyword self,

 

6-

 

Conclusione

Con lo studio completo delle proprietà statiche e dei metodi statici , si conclude la parte dedicata alle basi della programmazione ad oggetti in PHP: tutti i concetti fondamentali sono stati trattati con dovizia di particolari . Affronteremo lo step successivo, ovvero le strutture complesse formate dalla combinazione di più classi che prendono il nome di gerarchie di classi, ed osserveremo come è possibile condividere informazioni e risorse per creare applicazioni modulari.

 

 

Indicatori di visibilità: public

 

Le proprietà e le funzioni dell’indicatore di visibilità “public”

 

Come abbiamo imparato , le classi possono condividere le proprie funzionalità (costanti, proprietà e metodi) con le classi eredi. Questo è possibile perché tutte le proprietà ed i metodi utilizzati nelle classi che abbiamo analizzato sono stati dichiarati con la keyword public. Ciò significa, che essi sono disponibili pubblicamente, ovvero in ogni parte dello script: all’interno della classe stessa, all’esterno ed all’interno delle classi che ereditano.

Ma questa flessibilità può essere troppo fuorviante ed in alcuni casi dannosa, senza contare che la sola keyword public non permette la realizzazione di parecchi Design Patterns. Per questo motivo, esistono altri due indicatori di visibilità: protected e private. Ecco le descrizioni di tutti gli indicatori che abbiamo a disposizione:

 

# public: la proprietà o il metodo dichiarato come public è rispettivamente accessibile/ modificabile e richiamabile dall’interno della classe stessa, dall’esterno della classe e dall’interno delle classi che ereditano.

# protected: la proprietà o il metodo dichiarato come protected è rispettivamente accessibile/modificabile e richiamabile dall’interno della classe stessa e dall’interno delle classi che ereditano, ma non è accessibile dall’esterno della classe

# private: la proprietà o il metodo dichiarato come private è rispettivamente accessibile/ modificabile e richiamabile unicamente dall’interno della classe stessa

 

Vediamo ora degli esempi pratici che ci aiuteranno a capire le differenze che si ottengono dal comportamento di proprietà e metodi quando vengono dichiarati con uno specifico indicatore di visibilità.

 

Public

L’indicatore di visibilità public è il più semplice ed immediato dei tre. Dichiarando un elemento come public, si avrà il controllo completo sullo stesso in ogni situazione:

 

7-

Ricordiamo inoltre, che le costanti dichiarate all’interno di una classe sono sempre considerate pubbliche e quindi accessibili da qualsiasi posizione.

 

 

Superclassi, sottoclassi e overriding

 

Analizziamo le relazioni che intercorrono fra superclassi e sottoclassi

Dopo avere imparato come estendere le classi, come creare gerarchie composte e come utilizzare tutti i possibili indicatori di visibilità, è arrivato il momento di analizzare con maggiore dettaglio le relazioni che intercorrono tra superclassi e sottoclassi.

Come abbiamo già dichiarato in precedenza, le superclassi (anche definite classi “parent”, genitori o antenate) sono le classi che vengono estese e che offrono le loro funzionalità, mentre le sottoclassi sono l’esatto opposto, ovvero quelle classi che estendono le superclassi ereditandone le funzionalità.

Abbiamo inoltre imparato che i metodi pubblici e protetti vengono ereditati dalle sottoclassi, ma non abbiamo ancora visto cosa accade quando si dichiarano elementi con lo stesso namespace all’interno delle sottoclassi (ridefinizione o overriding).

Senza attuare delle particolari strategie, la proprietà o il metodo originale viene sovrascritto da quello nuovo:

 

8-

 

Ciò significa che con le conoscenze attuali, nello snippet precedente non abbiamo alcun modo di accedere al metodo sayHello della classe A attraverso le istanze della classe B.

Questa funzionalità diventa attuabile tramite la keyword parent, che unita all’operatore di risoluzione dell’ambito (“::”) ed al nome dell’elemento desiderato, permette di richiamare gli elementi della classe genitore direttamente nelle sottoclassi:

 

9-

 

In questo modo, abbiamo potuto richiamare il metodo sayHello della classe A direttamente nel metodo ridefinito presente nella classe B. Grazie all’uso della parola chiave parent, è possibile dunque condividere informazioni tra le classi senza l’occorrenza di riscrivere completamente un metodo nel caso in cui questo venga ridefinito.

Nel seguente esempio si può notare come, richiamando il metodo costruttore della classe parente sia possibile recuperare la fase di setting dei valori senza ripeterla inutilmente, ma aggiungendo solo le funzionalità veramente nuove:

 

10-

 

Ovviamente la keyword parent, oltre che con i metodi non statici, può essere usata in collaborazione con le costanti, con le proprietà statiche e con i metodi statici:

 

11-

 

Conclusione

I concetti di superclasse,sottoclasse e ridefinizione presentati  costituiscono il vero significato della programmazione orientata agli oggetti. Tutta la potenza, la flessibilità e la mantenibilità delle gerarchie OOP infatti, ruotano attorno a questi presupposti, che permettono di creare codice veramente modulare e soprattutto robusto.

Il concetto di ridefinizione (o overriding) attuabile tramite la keyword parent in particolare, permette di elevare il codice a livelli completamente nuovi rispetto al modello procedurale.

Tuttavia è addirittura possibile che accadano particolari situazioni in cui non si vuole attuare l’overriding: ciò è possibile in PHP tramite l’uso di una particolare keyword che analizzeremo dettagliatamente in seguito: quest’ultima prende il nome di final.

 

 

Impedire l’overriding: final

 

Come evitare la ridefinizione di un elemento attraverso l’uso della keyword final

Abbiamo imparato un altro dei concetti fondamentali della programmazione orientata agli oggetti, ovvero quello di overriding o ridefinizione di un elemento. Abbiamo analizzato tutte le possibili situazioni in cui è possibile attuare l’overriding e l’importanza della keyword parent.

Tuttavia, possiamo fare anche in modo di impedire l’overriding. Ad esempio, se prendiamo in considerazione una classe che contiene metodi che svolgono operazioni fondamentali (come la connessione ad un database, il parsing di documenti XML e così via), possiamo decidere di non permettere la ridefinizione di questi metodi che potrebbe causare instabilità all’interno della gerarchia e di conseguenza di tutta l’applicazione.

Per questo ci occorre una strategia per impedire l’overriding. Questo è possibile grazie alla parola chiave final, che utilizzata in combinazione con l’indicatore di visibilità desiderato e con il nome del metodo, implica che quest’ultimo non potrà essere ridefinito dalla classe eredi. Ecco un esempio:

 

12-

 

Come possiamo vedere, i metodi dichiarati con la keyword final si comportano esattamente come le controparti normali. La differenza occorre quando tentiamo di ridefinire i metodi in questione:

 

13-

 

Il tutto risulterà in un Fatal Error che ci dirà che non è possibile ridefinire il metodo sayHello della classe MyClass, poichè quest’ultimo è stato dichiarato come final:

 

14-

 

Classi final

 

Una particolarità interessante offerta dalla keyword final è che quest’ultima, oltre che con i metodi, può essere utilizzata in collaborazione con le classi. Dichiarando una classe come final infatti (la parola chiave “final” deve precedere il nome della classe), quest’ultima non potrà essere estesa da nessuna sottoclasse:

 

15-

 

Anche in questo caso, tentare di estendere la classe MyClass porta ad un Fatal Error:

 

16-

 

La decisione di dichiarare le classi come final potrebbe apparire come priva di significato, dato che il nucleo della OOP si basa sull’estensione delle classi, ed effettivamente è un criterio che va usato con cautela. Tuttavia, ci sono parecchi casi reali dove dichiarare le classi come final rappresenta la soluzione migliore e più sicura per la stabilità dell’applicazione. Ad esempio, se abbiamo una gerarchia di classi per gestire le diverse tipologie di utenti, potremmo avere una classe SimpleUser che definisce un utente normale ed una classe AdministerUser che definisce gli amministratori con dei privilegi speciali. Sarebbe meglio fare in modo che quest’ultima classe non possa essere estesa da ulteriori sottoclassi, che implementerebbero tutti i suoi privilegi.

 

Conclusione

Il prossimo step comprende due argomenti avanzati, la cui conoscenza è fondamentale nella programmazione orientata agli oggetti di PHP: le classi astratte e le interfacce, tramite le quali è possibile creare vere e proprie API, uniformare il comportamento delle classi ed astrarre le funzionalità da esse offerte: l’ideale per gestire i lavori e le collaborazioni in Team.

 

 

Utilizzare le classi astratte

 

Vediamo come si comportano le classi astratte in azione: esempi d’uso e approfondimenti

Forti della panoramica teorica della precedente lezione, possiamo ora passare ad osservare le classi astratte in azione. Prendiamo come esempio quello dichiarato precedentemente, in cui i tre Team di sviluppo creano una gerarchia di classi e vogliono condividere le stesse API, elevandolo con un esempio concreto.

Supponiamo che la classe astratta di base (che chiameremo Product) contenga dei metodi per creare ed ottenere informazioni su di un prodotto, mentre le classi InProduct ed OutProduct si occuperanno di fornire informazioni rispettivamente sui prodotti locali ed esterni, così come dell’acquisto e della vendita.

 

17-

 

La classe Product, deve essere necessariamente estesa tramite nuove sottoclassi che devono obbligatoriamente ridefinire i suoi metodi astratti, in questo caso quelli denominati buyProduct (comprare un prodotto locale/esterno) e sellProduct (vendere un prodotto locale/esterno):

 

18-

 

Ovviamente, le funzioni ed i metodi utilizzati internamente sono inventati a puro scopo illustrativo (in uno scenario reale possono essere dichiarati, ad esempio, in altri file dell’applicazione). Ciò che è importante capire, è che nonostante le classi InProduct ed OutProduct siano create da diversi team di sviluppo, esse assumono una forma comune, coerente con quella indicata dalla classe astratta Product.

Tutte e tre le classi dunque, possono essere utilizzate nella stessa applicazione per costituire una API:

 

19-

 

Conclusione

Abbiamo imparato ad utilizzare le classi astratte e soprattutto a capirne l’importanza. Tuttavia, è errato credere che basti implementare delle classi astratte per ottenere un’applicazione solida ed uniforme, ma occorre progettare ogni singola caratteristica nel dettaglio fin dalle basi dell’applicazione stessa: ne consegue che le classi astratte sono solo il mezzo utile al raggiungimento di questo scopo. Ma queste classi particolari non sono le uniche componenti utili alla creazione di API uniformi:  vedremo  le interfacce, nuovi strumenti al servizio delle infinite possibilità della OOP.

 

 

Utilizzare le interfacce

 

Come utilizzare al meglio le interfacce nella programmazione ad oggetti

Dopo avere acquisito la conoscenza delle teorie e delle sintassi che stanno alla base delle interfacce, passiamo ora ad analizzare uno scenario reale in cui queste ultime vengono utilizzate.

Assumiamo, come nell’esempio dedicato alle classi astratte, che un Team di sviluppatori denominato “A” stia lavorando ad una classe User che permette di creare un utente e gestire le sue caratteristiche, mentre il Team “B”, utilizzando le stesse regole, vuole aggiungere funzionalità leggermente più avanzate personalizzate, come il counting degli utenti e dei messaggi testuali. Entrambe le classi, per ottenere una struttura comune, implementano l’interfaccia denominata IUser:

 

20-

Ecco la classe UserA definita dal gruppo “A”:

 

21-

 

Questa è l’implementazione desiderata dal Team “A”. Ora ecco la controparte del Team “B”:

 

22-

 

Come possiamo notare, la classe UserB è leggermente più complessa e nutrita rispetto alla classe UserA: la prima tiene traccia di quanti utenti sono stati creati e stampa dei messaggi ad ogni operazione, sia di getting che di setting. Ciò che conta però, è che entrambe le classi hanno una forma comune, sia le istanze della classe UserA che quelle della classe UserB possono essere intercambiate ed integrate nella stessa applicazione senza produrre incompatibilità o errori.

Inoltre, dato che entrambe le classi implementano l’intefaccia IUser, è possibile tramite i metodi setPartner di ognuna, impostare un partner di tipo UserA ad un’istanza di tipo UserB e vice versa.

 

Conclusione

 

Anche in questo caso, come in quello delle classi astratte, non si deve pensare che basti utilizzare delle interfacce per ottenere applicazioni prive di ogni instabilità, ma occorre prestare attenzione a tutte le fasi dello sviluppo del progetto. Le classi astratte e le interfacce, se usate adeguatamente, possono portare enormi benefici alle nostre gerarchie OOP.

Si chiude la sezione dedicata all’astrazione della classi. A questo punto , si è già molto probabilmente acquisita la capacità di creare gerarchie solide e conformi ai punti chiave della OOP. Tuttavia, esistono ancora diversi concetti che devono essere appresi per otternere una conoscenza a 360 gradi, che per la loro natura eteroegenea non possono essere raggrupati in una sezione comune. Per questo, prossimamente , saranno appunto affrontati tutti gli extra offerti dalla programmazione orientata agli oggetti di PHP, a partire dai riferimenti degli oggetti.

 

 

Riferimenti degli oggetti

 

Capire e lavorare con i riferimenti degli oggetti. Differenze fra valori, riferimenti e identificatori

Una differenza molto importante presente in ogni linguaggio di programmazione è sicuramente quella che intercorre tra valore e riferimento. Come sappiamo, se si lavora con i valori si ha a che fare con vere e proprie “copie” dei dati, mentre se si stanno utilizzando i riferimenti, si ha a che fare con i dati veri e propri: eventuali modifiche influenzeranno le variabili o i dati reali.

Dalla versione 5 di PHP, gli oggetti non vengono più trattati per valore, ma per riferimento (in realtà, come spiegheremo tra qualche riga, più che riferimenti si tratta di copie dello stesso identificatore univoco). Questo, a parte tutte le migliorie interne al motore del linguaggio, implica che se si passa un oggetto ad una funzione o lo si assegna ad un’altra variabile, quello che verrà utilizzato sarà il suo riferimento e dunque l’oggetto verrà modificato. Di seguito troviamo degli esempi pratici che spiegano molto bene questo concetto. Partiamo dall’assegnazione di un oggetto con una variabile:

 

23-

 

Entrambe le variabili $myClass_1 e $myClass_2 si riferiscono alla stessa posizione, dunque eventuali modifiche o aggiunte ad una di esse si ripercuoteranno anche sull’altra. Vediamo ora il caso in cui passiamo gli oggetti come parametri delle funzioni:

 

24-

 

Anche in questo caso, ciò con cui si lavora è il riferimento e non il valore, dunque l’oggetto originale viene alterato.

 

Riferimento vs identificatore

 

Come ho dichiarato in precedenza, anche se il comportamento è pressoché identico, in realtà nel caso degli oggetti non si ha a che fare con veri e propri riferimenti, ma con copie dello stesso identificatore. Ogni variabile istanza possiede un identificatore univoco (che chiameremo id): quando si assegna l’oggetto ad una nuova variabile o lo si passa ad una funzione, questo id verrà utilizzato come riferimento:

 

25-

 

Ovviamente, anche con gli oggetti è possibile utilizzare il riferimento vero e proprio tramite l’operatore &. In questo caso verrà utilizzato il riferimento stesso: entrambe le variabili si riferiranno alla stessa posizione:

 

26-

 

Conclusione

 

Bisogna tenere sempre in mente che in PHP5 gli oggetti vengono trattati per riferimento: questo concetto è di vitale importanza per le nostre applicazioni. Gli sviluppatori che non provengono dalla versione 4 di PHP molto probabilmente troveranno questo comportamento a dir poco naturale ed “ovvio”, mentre chi è abituato a trattare gli oggetti per valore dovrà svolgere qualche piccolo test per prendere confidenza con questo nuovo (e sicuramente migliore) stile di programmazione.

 

 

Confrontare gli oggetti

 

Le varie tecniche per confrontare tra loro gli oggetti: uguaglianza ed identità

L’operazione di confronto tra due oggetti, per quanto immediata possa sembrare, racchiude svariate competenze che vanno oltre al semplice concetto di confronto di variabili. Innanzitutto occorre sapere che in PHP esistono due operatori per confrontare due variabili tra di loro:

 

# l’operatore di uguaglianza (“==”): restituisce true se le due variabili contengono lo stesso valore, anche se sono di tipo diverso

# l’operatore di identità (“===”): restituisce true se le due variabili contengono lo stesso valore e sono dello stesso tipo

 

Ciò significa che, ad esempio:

 

27-

 

Questa regola vale per il confronto tra tutti i tipi semplici di dato. Tuttavia, nel caso degli oggetti, nonostante gli operatori siano i medesimi, occorrono nuove regole per il confronto. Eccole:

 

# l’operatore di uguaglianza: restituisce true se i due oggetti hanno le stesse coppie proprietà/valore e sono istanze della stessa classe

# l’operatore di identità: restituisce true se e solo se i due oggetti si riferiscono alla stessa istanza della classe

 

Consci di queste nuove direttive, possiamo ora andare ad analizzare i casi pratici di confronti. Partiamo utilizzando l’operatore di uguaglianza:

 

28-

 

Vediamo ora l’operatore di identità, che anche nel caso degli oggetti, è assai più restrittivo del precedente:

 

29-

 

Come possiamo notare, l’unico modo per ottenere un risultato positivo nel confronto tra oggetti utilizzando l’operatore di identità è che essi costituiscano la stessa istanza.

 

Conclusione

Per quanto rara possa essere l’operazione di confronto degli oggetti, essa presenta delle caratteristiche insolite rispetto alle semplici variabili, come abbiamo poututo vedere in questa lezione. Essere consci delle regole di confronto valide per le istanze è molto importante in uno scenario reale. Nella prossima lezione, l’ultima dello “step” degli extra, analizzeremo un nuovo operatore che ci permetterà di ottenere indicazioni sul tipo di un determinato oggetto.

 

 

Il tipo degli oggetti

 

Instanceof: come ottenere il tipo dei nostri oggetti e scoprire se un oggetto è un’istanza di una determinata classe

Per scoprire se un oggetto è un’istanza di una determinata classe, l’operatore instanceof è quello che fa al caso nostro. Basta usarlo in combinazione con la variabile desiderata e il nome della classe di cui si vuole verificare l’appartenenza:

 

$instance instanceof MyClass

Ecco un semplice esempio:

 

30-

 

La variabile $myClass_1 è un’istanza della classe MyClass, mentre la variabile $myOtherClass_1 non lo è.

 

Operatore instanceof e gerarchie

 

Anche l’operatore instanceof agisce sulle gerarchie di classi: ciò significa che se una classe eredita da un’altra classe, essa avrà comunque il tipo della classe da cui eredita, in aggiunta al proprio. Questo concetto è valido anche nel caso delle interfacce: è possibile usare l’operatore instanceof in collaborazione con il namespace di un’interfaccia e, se la classe la implementa, il risultato sarà true.

Ecco degli esempi:

 

31-

 

Come possiamo notare, l’oggetto $myClass_1 è un’istanza della classe MyClass ma non della classe MyOtherClass, mentre l’oggetto $myOtherClass_1 è un’istanza di entrambe le classi. L’oggetto $myThirdClass_1 implementa l’interfaccia ICommon, dunque l’operatore instanceof ha esito positivo.

 

Conclusione

 

L’operatore instanceof non è l’unica modalità offerta da PHP per analizzare la classe di appartenenza di un’istanza (le funzioni is_a, get_class, is_subclass_of e get_parent_class sono tutte adatte a questo scopo), ma costituisce l’alternativa più valida tra tutte, dunque per qualsiasi compito di checking del tipo di un oggetto il suo utilizzo è fortemente consigliato, direttamente dai creatori del linguaggio, rispetto alle altre funzioni.

 

 

I metodi magici – Seconda parte

 

La lista dei metodi magici. Seconda  parte: sleep, wakeup, toString, set_state, invoke, clone

Continuiamo l’analisi dei rimanenti metodi magici, dopo quelli affrontati nella lezione precedente.

 

__sleep e __wakeup

Questi due metodi magici vengono richiamati rispettivamente in fase di serializzazione e deserializzazione degli oggetti. Il metodo __sleep deve restituire un array contenente i nomi delle proprietà da serializzare (altrimenti verrà generato un errore di tipo E_NOTICE) e si usa generalmente per operazioni di cleanup, mentre il metodo __wakeup svolge il compito opposto: può essere usato, ad esempio, per riaprire le connessioni ai database o alle risorse esterne.

 

32-

 

__toString

Il metodo magico __toString è molto utile. Se si stampasse un’istanza con le funzioni echo o print, si otterrebbe una stringa del tipo Object #… oppure un errore di tipo Catchable Fatal Error, perchè di default gli oggetti non sono dati stampabili con regole precise. Queste regole possiamo deciderle noi programmando cosa deve accadere quando viene stampata un’istanza:

 

33-

 

__set_state e __invoke

Questi due metodi magici sono molto probabilmente i meno utilizzati tra tutti quelli disponibili. Il primo viene azionato quando si esporta un oggetto tramita la funzione var_export ed accetta un array che avrà le coppie key/value impostate ai nomi/valori delle proprietà esportate. Il secondo (disponibile a partire dalla versione 5.3.0) viene richiamato quando si usa un oggetto come una funzione.

 

34-

 

__clone

Come abbiamo visto nella lezione dedicata alla clonazione degli oggetti, è possibile stabilire cosa deve accadere quando questa situazione si verifica. La parte interessante del metodo __clone è rappresentata dal fatto che al suo interno la pseudovariabile $this si riferisce all’istanza clonata, e quindi si ha l’immediata possibilità di compiere operazioni con essa:

 

35-

 

Conclusione

 

Abbiamo potuto osservare dettagliatamente tutti i metodi magici dichiarabili all’interno delle classi con PHP5 e soprattutto la loro assoluta importanza. Un metodo magico può riscuotere un ruolo importantissimo nelle gerarchie di oggetti di qualsiasi tipologia di applicazione, poiché permette di controllare con precisione una determinata situazione altrimenti inaccessibile.

Conoscere e padroneggiare questi metodi (o almeno i più importanti) è di fondamentale importanza per lo sviluppo di applicazioni OOP avanzate.

Termina la parte teorica della guida. A questo punto tutti i concetti fondamentali della programmazione orientata agli oggetti offerta da PHP sono stati dettagliatamente affrontati. È arrivato dunque il momento di affrontare la parte pratica conclusiva, che ci permetterà di realizzare un’applicazione OOP reale mettendo in pratica la maggior parte dei concetti che abbiamo imparato .

 

 

Analisi dell’applicazione FormCheck

 

Studio e pianificazione di un’applicazione pratica: la validazione di un form

Adesso ci dedichiamo  alla descrizione pratica di programmazione di una piccola applicazione Web. Per rappresentare un’applicazione reale ho scelto uno dei compiti server-side più comuni che è possibile realizzare con PHP: la validazione di un form. Questa task può essere rappresentata in mille modalità differenti (sono molte le librerie open source che permettono la validazione di un form tramite PHP), ma solo analizzandone praticamente ogni singolo aspetto sarà possibile apprezzare i vantaggi derivanti da un modello OOP ed affinare così le proprie capacità. Vediamo come sarà composta la nostra applicazione che d’ora in avanti verrà denominata FormCheck.

Per seguire meglio gli esempi è possibile scaricare sia il pacchetto che contiene l’applicazione, sia il pacchetto che contiene l’estensione e che tratteremo alla fine del primo esempio. L’applicazione può essere

 

Il form

Il form di questa applicazione sarà molto semplice e dunque costituito solo da campi di testo (elementi input di tipo text), dato che il nucleo fondamentale sarà rappresentato dallo script che contiene le gerarchie di classi. Il nostro modulo sarà dunque composto dai seguenti campi:

 

# un nome (“name”) che dovrà contenere solo caratteri alfanumerici e la cui lunghezza dovrà essere compresa tra i 4 ed i 15 caratteri

# un cognome (“lastname”) che come il precedente, dovrà contenere solo caratteri alfanumerici e la cui lunghezza dovrà essere compresa tra i 4 ed i 15 caratteri

# un’ e-mail (“email”) che dovrà essere scritta nella forma comune “mailname@mailserver.mailext”

# un anno di nascita (“year”) che per ovvi motivi dovrà essere superiore al 1900

Tutto questo verrà inserito in una semplice pagina HTML, che interagirà con lo script PHP.

 

La gerarchia di classi

 

Sarà compito della parte server-side stabilire se tutti i campi del form sono stati inviati correttamente. Ciò accadrà tramite la classe FormCheck, la classe astratta AFormCheck e l’interfaccia IFormCheck. Ecco in breve i loro compiti principali:

 

# interfaccia IFormCheck: si occuperà di definire i namespaces dei metodi pubblici utilizzabili dalle classi della gerarchia. Ciò ci permetterà di uniformare il comportamento nel caso di più classi realizzate per adempiere al medesimo scopo, come vedremo nella seconda parte di questa parte pratica conclusiva

# classe astratta AFormCheck: conterrà le proprietà fondamentali (pubbliche, protette e private), il metodo costruttore che sarà condiviso da ogni sottoclasse ed i metodi principali che si occuperanno dell’erroring e del tracking, ovvero della gestione degli errori presenti nei dati forniti dagli utenti

# classe FormCheck: la classe finale utilizzabile direttamente dallo sviluppatore, che conterrà tutti i metodi ridefiniti richiesti dall’interfaccia IFormCheck e che si occuperà della validazione dei dati forniti dagli utenti

 

Se tutti i campi forniti allo script PHP soddisfano le nostre condizioni, allora verrà visualizzato un messaggio che indicherà che l’operazione ha avuto un esito positivo, ed i dati inseriti verranno pubblicati. In caso contrario, verrà tenuta traccia sia di ogni campo inviato correttamente sia di ogni campo errato, in modo che l’utente abbia la possibilità di effettuare modifiche mirate a soddisfare tutti requisiti.

 

Conclusione

Prima di passare alla lezione successiva, è opportuno fare diverse considerazioni in merito a questa applicazione. In primo luogo, il metodo rappresentato in questa parte della guida rappresenta solo una delle tante strade con cui si potrebbe procedere: sta allo sviluppatore modificare i vari metodi o comportamenti interni per adattarli al meglio alle proprie esigenze.

Inoltre, il compito della validazione di un form è un punto di fondamentale importanza per le applicazioni moderne, che nella maggioranza dei casi implica la presenza di un Database Management System. La sicurezza è IL requisito fondamentale in questo tipo di applicazioni, e non va assolutamente trascurata, pena l’instabilità del sistema e la perdita di dati sensibili. Sebbene siano presenti dei validi controlli nelle classi FormCheck, essi non vogliono essere un punto di riferimento assoluto per la sicurezza. Ciò che vuole essere trasmessa è unicamente l’importanza della OOP in PHP.

 

 

Comporre la gerarchia – prima parte

 

Creare l’interfaccia IFormCheck e la classe astratta AFormCheck per la nostra applicazione di esempio

La nostra gerarchia sarà composta da 3 parti fondamentali: l’interfaccia IFormCheck, la classe astratta AFormCheck che implementa la precedente e la classe finale FormCheck. In questa lezione vedremo come costruire l’interfaccia completa e la prima parte della classe astratta. Partiamo dall’interfaccia IFormCheck, che assume la seguente forma:

 

36-

 

Come possiamo notare, quest’ultima contiene tutti i metodi pubblici che la classe FormCheck dovrà ridefinire. Ovviamente i metodi checkName, checkLastname, checkEMail e checkYear avranno il compito di validare rispettivamente il nome, il cognome, l’e-mail e l’anno di nascita forniti dall’utente. Il metodo checkAll è decisamente il più interessante: richiamandolo, ci si assicura che tutti i precedenti controlli siano stati effettuai. checkAll restituirà true nel caso in cui l’esito sia positivo e false nel caso contrario. In entrambe le situazioni, degli opportuni messaggi (gestiti tramite la classe astratta AFormCheck) verranno stampati.

Infine, il metodo setErrorMsgs servirà a personalizzare i messaggi di errore da visualizzare per ogni campo il cui valore fornito risulti errato.

 

La classe astratta AFormCheck

 

Il compito fondamentale della classe AFormCheck è quello di gestire il tracking ed il reporting degli errori che si presentano nei dati ricevuti dagli utenti. La classe è dichiarata come abstract perchè non deve essere utilizzata direttamente dall’utente, ma vuole essere solamente un “wrapper” di funzionalità fondamentali da condividere con più classi.

 

Per questo motivo AFormCheck conterrà:

 

# le proprietà pubbliche, private e protette fondamentali

# il metodo costruttore che inizializza le precedenti ricavando i dati dai campi dell’array superglobale $_POST

# i metodi trackErrorMsg, getErrorMsg ed internalError, che analizzeremo dettagliatamente successivamente

Ecco il codice della prima parte della classe AFormCheck (proprietà e costruttore):

 

37-

 

Le proprietà pubbliche name, lastname, email e year verranno impostate ai rispettivi valori dell’array superglobale $_POST in fase di costruzione dell’istanza. L’array errorMsgs contiene tutti i messaggi da stampare nel caso si presenti un errore con uno o più campi del form.

La proprietà privata err servirà per tenere traccia degli errori: nel caso in cui il suo valore risulti inalterato, significa che non si sono presentate inesattezze. L’array clean infine, verrà popolato con i dati che hanno passato la validazione, in modo che possano essere usati in tutta tranquillità.

La seconda parte della classe AFormCheck, è composta da metodi per la registrazione e la gestione degli errori. Ecco il codice:

 

38-

 

Il metodo trackErrorMsg, che verrà richiamato dai metodi pubblici della classe FormCheck, si occupa della registrazione degli errori. Se esiste nell’array errorMsgs un campo con il nome passato come parametro (ad esempio name, lastname, email e year) verrà registrato il rispettivo messaggio di errore. In caso contrario, verrà generato un errore di tipo E_WARNING per indurre lo sviluppatore a comprendere che il campo specificato non è attualmente esistente, tramite il metodo protetto internalError.

Infine, il metodo getErrorMsg si occupa di stampare l’errore o la lista di errori registrati, se esistono, oppure di visualizzare un messaggio che indica che tutti i campi del form sono stati inviati correttamente.

 

 

Istanziare la classe FormCheck

 

FormCheck in azione: come utilizzare in pratica l’applicazione creata

Con poche righe di HTML possiamo creare una pagina che contenga il form che ci consentirà di inviare i dati allo script PHP e di vedere la nostra classe FormCheck all’opera:

 

39-

 

Una volta premuto il pulsante “Invia”, i dati verranno inviati tramite il metodo HTTP post, e gestiti sul server tramite il seguente snippet di codice:

 

40-

 

La variabile form è la nostra istanza della classe FormCheck. Se il metodo checkAll restituisce false, viene richiamata la funzione exit per terminare lo script. Non sarà necessario fornire alcun messaggio, perché la classe si occupa di stampare tutte le informazioni necessarie agli utenti. Se invece checkAll restituisce true, vengono stampati tutti i dati filtrati e pronti per l’uso presenti nella proprietà pubblica clean.

 

Per una prova pratica immediata, è possibile ad esempio inserire i seguenti dati per ottenere un risultato positivo:

 

# Nome: “George”

# Cognome: “White”

# E-Mail: “george.white@server.com”

# Anno di nascita: 1970

Ed il server risponderà con il seguente responso:

 

Il nome è stato inviato correttamente.

Il cognome è stato inviato correttamente.

[…]

Contrariamente, fornendo dati che non rispettano le condizioni desiderate:

 

# Nome: “Sam”

# Cognome: “Whitewhitewhitewhite”

# E-Mail: “sam.white.com”

# Anno di nascita: “1870”

 

Otterremo il seguente messaggio dallo script PHP:

 

Errore!

Il nome deve essere composto da caratteri alfanumerici  e deve contenere dai 4 ai 10 caratteri al massimo.

[…]

 

Download

 

Ora che abbiamo analizzato in ogni dettaglio la nostra applicazione pratica, è arrivato il momento di effettuare delle prove manuali sul proprio Pc. Tramite questo link è possibile scaricare tutto il pacchetto completo del nostro esempio. L’archivio contiene il codice sorgente della gerarchia FormCheck e la pagina HTML che costituisce il nostro form.

Il mio consiglio personale è quello di analizzare attentamente il codice di tutti i componenti della gerarchia e provare a modificare i comportamenti a seconda delle proprie preferenze.

 

 

MoreFormCheck in azione

 

Visualizzare in pratica le azioni e il funzionamento della nostra applicazione. Download dei pacchetti sorgenti.

Per visualizzare praticamente gli effetti della nuova classe MoreFormCheck occorre creare un altro form HTML, identico al precedente con la sola aggiunta di due campi input di tipo “password”. Anche di questo form abbiamo preparato un esempio online. Anche in questo caso, fornendo dati che rispettano le nostre condizioni:

 

# Nome: “George”

# Cognome: “White”

# E-Mail: “george.white@server.com”

# Anno di nascita: 1970

# Password (1 e 2): “ahy8978yha”

Il server risponderà con un responso positivo:

 

Il nome è stato inviato correttamente.

Il cognome è stato inviato correttamente.

[…]

Mentre se fornissimo una password sbagliata, avremo una nuova, corretta segnalazione:

 

La password non è corretta.

 

Download

Anche per questa ulteriore estensione della nostra applicazione, ho preparato un pacchetto pronto per essere scaricato. Quest’ultimo contiene il codice delle precedenti gerarchie FormCheck, il codice della classe MoreFormCheck ed infine il nuovo form HTML.

 

Conclusione

Si conclude la nostra Guida alla programmazione ad oggetti con PHP5. È impressionante notare come con quest’ultimo esempio, sia stato possibile aggiungere funzionalità del tutto nuove senza modificare minimamente il codice precedente. Il vantaggio principale della OOP risiede proprio in questo modo differente di intendere e comporre il nostro codice.

Tutti concetti, teorici e pratici, che costtituiscono la OOP di PHP5 sono stati analizzati accuratamente. Come in ogni altro caso che riguarda la programmazione, la dedizione e la pratica completeranno perfettamente il quadro.

Lascia una risposta