Tutto sulla parola chiave statico

Oggi impareremo come usare la parola chiave 'statica' in PHP. Andremo oltre le basi e costruiremo alcuni esempi. È giunto il momento di aggiungere questa caratteristica linguistica interessante al tuo bagaglio di abilità di sviluppo web.


1 Un esempio rapido

Facciamo prima un breve esempio per vedere l'effetto dell'uso della parola chiave statica.

Immagina di scrivere una funzione che ricordi quante volte è stata chiamata. Se non hai familiarità con la parola chiave 'statica', potresti ricorrere all'utilizzo di alcune variabili globali:

 $ call_me_count = 0; function call_me () global $ call_me_count; $ Call_me_count ++; echo "Mi hai chiamato $ call_me_count volte 
\ n "; // output => Mi hai chiamato 1 volte call_me (); // output => Mi hai chiamato 2 volte call_me (); // output => Mi hai chiamato 3 volte call_me (); // output => Mi hai chiamato 4 volte call_me ();

Solo perché questo funziona non significa che dovresti scrivere il codice in questo modo. In generale, le variabili globali sono disapprovate. Non è una buona idea avere variabili globali fluttuanti, che alcune funzioni utilizzino solo in privato.

Ora inserisci la parola chiave 'statica'. Lo stesso codice può essere riscritto in questo modo:

 function call_me () // una variabile statica static $ call_me_count = 0; $ Call_me_count ++; echo "Mi hai chiamato $ call_me_count volte 
\ n "; // output => Mi hai chiamato 1 volte call_me (); // output => Mi hai chiamato 2 volte call_me (); // output => Mi hai chiamato 3 volte call_me (); // output => Mi hai chiamato 4 volte call_me ();

Stesso risultato, niente più variabili globali. Ma come funziona esattamente??

Normalmente, tutte le variabili locali all'interno di una funzione vengono distrutte una volta che la funzione ritorna. Le parole chiave "statiche" consentono a PHP di sapere di mantenere viva la variabile. Quindi, al prossimo richiamo della funzione, viene mantenuto il valore all'interno della variabile.


2 Valori iniziali validi

Come visto nell'esempio precedente, quando abbiamo assegnato il valore di 0 alla variabile, in realtà non è stata eseguita un'istruzione di assegnazione. Imposta solo il valore iniziale per la variabile. Potrebbe sembrare la stessa cosa, ma c'è una leggera differenza. La variabile può essere inizializzata solo su un valore fisso e non su un'espressione.

Vediamo alcuni esempi di valori iniziali validi e non validi. Per prima cosa, esaminiamo i numeri:

 function foo () // valid static $ a = 9; // causa l'errore di analisi statico $ a = sqrt (81); // statico valido $ a = 3,14; // causa l'errore di analisi statico $ a = pi (); // causa l'errore di analisi statico $ a = 1 + 3; 

Come puoi vedere, nemmeno le operazioni matematiche di base sono consentite. Tutto ciò che puoi assegnare è un numero fisso.

Possiamo anche assegnare stringhe:

 function foo () // valid static $ a = "; // valido static $ a = 'hello'; // causa un errore di parsing statico $ a = strtoupper ('hello'); // causa un errore di parsing statico $ a = 'Ciao mondo'; 

Ancora una volta, è necessario che le stringhe siano fisse e non è consentita nemmeno la concatenazione di base.

Anche Booleans, Arrays e Constants funzioneranno:

 define ("SOME_CONSTANT", 789); function foo () // valid static $ a = array (1,2,3); // static static $ a = SOME_CONSTANT; // statico valido $ a = array (1,2, 'three', array ('foo' => 'bar')); // statico valido $ a = true; 

3 Creazione di una funzione alternativa ()

Ora che sappiamo come funzionano le variabili statiche all'interno delle funzioni, costruiamo qualcosa di utile con esso.

Ecco una semplice pagina HTML con una semplice tabella in esso:

    Il mio tavolo    
ID Nome Categoria
1 Mela Frutta
2 Carota Verdura
3 Cane Animale
4 Forno Apparecchio

Il risultato è:


Ora aggiungiamo un css e facciamo alternare le righe al colore:

    Il mio tavolo     
ID Nome Categoria
1 Mela Frutta
2 Carota Verdura
3 Cane Animale
4 Forno Apparecchio

Ora sembra così:


Se i dati provenivano da un database e le righe della tabella sono state generate in un ciclo, è necessario aggiungere del codice per poter impostare le classi CSS alternative su ogni riga. La maggior parte delle persone andrebbe avanti e creerebbe una variabile all'interno di quel ciclo, aggiungendo un'istruzione condizionale o ternaria per continuare a alternare il suo valore.

Tuttavia, costruiremo una soluzione più elegante e riutilizzabile. Creeremo una funzione denominata alternate () che utilizza il concetto di variabili statiche.

 funzione alterna ($ a, $ b) statica $ alt = falso; // inverte il valore di alt (true <=> false) $ alt =! $ alt; se ($ alt) return $ a; // restituisce il primo valore else return $ b; // restituisce il secondo valore // Esempio di utilizzo: // output: odd echo alternate ('odd', 'even'); // output: even echo alternate ('odd', 'even'); // output: odd echo alternate ('odd', 'even');

Chiamiamo la funzione con due argomenti. Ogni volta che viene chiamato, restituisce uno degli argomenti in modo alternato. Ottiene ciò mantenendo un valore booleano in una variabile statica chiamata $ alt. Ogni volta che capovolge questo valore di variabili, per determinare quale dei due argomenti restituire.

Quindi, usiamolo nella nostra pagina, mettendo tutto insieme:

  false) $ alt =! $ alt; se ($ alt) return $ a; // restituisce il primo valore else return $ b; // restituisce il secondo valore $ rows = array (array (1, 'Apple', 'Fruit'), array (2, 'Carrot', 'Vegetable'), array (3, 'Dog', 'Animal') , array (4, 'Oven', 'Appliance')); ?>    Il mio tavolo     
ID Nome Categoria
', $ row); ?>

E il risultato finale è lo stesso:



4 Migliorare la nostra funzione alternativa ()

La funzione che abbiamo creato funziona bene, se la usiamo solo in un punto nei nostri script. C'è un piccolo problema con esso, tuttavia. Se lo usiamo in più posti, o in cicli annidati, potrebbe non restituire i valori nell'ordine che intendevamo. Diamo un'occhiata a questo codice per dimostrare questo problema:

 // a echo alternate ('a', 'b'). "
\ n "; // b echo alternate ('a', 'b')."
\ n "; // a echo alternate ('a', 'b')."
\ n "; // even // (il secondo valore viene restituito per primo!) echo alternate ('odd', 'even')."
\ n "; // odd echo alternate ('odd', 'even')."
\ n "; // bar // (stesso problema) echo alternate ('foo', 'bar')."
\ n "; // a // (l'ultima volta era" a ") echo alternate ('a', 'b')."
\ N ";

La nostra funzione deve essere consapevole che viene chiamata da diversi luoghi e assicurarsi di restituire i valori di conseguenza. Possiamo farlo aggiungendo un ultimo parametro opzionale, per assegnare un numero ID. E passiamo un ID univoco da ogni luogo diverso da cui lo chiamiamo, per evitare questi conflitti:

 funzione alternata ($ a, $ b, $ id = 0) statico $ alt = array (); if (! isset ($ alt [$ id])) $ alt [$ id] = falso;  $ alt [$ id] =! $ alt [$ id]; if ($ alt [$ id]) return $ a;  else return $ b;  // a echo alternate ('a', 'b', 1). "
\ n "; // b echo alternate ('a', 'b', 1)."
\ n "; // a echo alternate ('a', 'b', 1)."
\ n "; // odd echo alternate ('odd', 'even', 2)."
\ n "; // anche echo alternate ('odd', 'even', 2)."
\ n "; // foo echo alternate ('foo', 'bar', 3)."
\ n "; // b echo alternate ('a', 'b', 1)."
\ N ";

Questa volta utilizziamo un array come variabile statica. Trasporterà un valore booleano unico per ogni numero ID diverso che è stato passato. Ciò gli consente di restituire i valori nell'ordine corretto.


5 membri della classe statica

La parola chiave "statica" non viene utilizzata solo all'interno delle funzioni. In realtà è abbastanza comune nella programmazione orientata agli oggetti. Possono esserci membri statici e metodi. Per prima cosa vedremo come funzionano i membri statici.

Ecco la sintassi:

 class Foo // un membro statico public static $ a = 0; // un membro normale pubblico $ b = 0; public function bar () // accesso al membro statico self :: $ a; self :: $ a ++; auto :: $ a = 3; // membro normale: $ this-> b; $ This-> b ++; $ this-> b = 3;  // accesso al membro statico // dall'esterno Foo :: $ a; Foo :: $ a ++; Foo :: $ a = 3; $ obj = new Foo (); // accesso al membro normale $ obj-> b; $ Obj-> b ++; $ obj-> b = 3;

Nota come abbiamo usato la parola chiave 'self ::' davanti alla variabile statica per accedervi all'interno della classe, piuttosto che '$ this'. Inoltre, quando utilizzato nell'ambito esterno, non è necessario creare un'istanza dell'oggetto prima di poter accedere alle variabili statiche. Tuttavia, è possibile accedere ai normali membri della classe solo dopo averne creato un'istanza.


6 Una classe che si afferma

Ricorda il nostro primo esempio in cui abbiamo avuto una funzione che ha tenuto conto di quante volte è stata chiamata? Applichiamo ora lo stesso principio alla programmazione orientata agli oggetti.

Questa classe avrà la possibilità di contare quante volte il totale è stato creato:

 class Foo // il nostro contatore dell'istanza public static $ counter = 0; // per funzionare come ID autoincrement public $ id = 0; // la funzione di costruzione public function __construct () // count counter self :: $ counter ++; // salva lo stesso numero // come id di questo oggetto $ this-> id = self :: $ counter;  // output: 0 echo Foo :: $ contatore. "\ N
"; $ a = new Foo (); // output: 1 echo Foo :: $ contatore." \ n
"; $ b = new Foo (); // output: 2 echo Foo :: $ contatore." \ n
"; $ c = new Foo (); // output: 3 echo Foo :: $ contatore." \ n
"; // output: 2 echo $ b-> id;

Ogni volta che viene creato un nuovo oggetto, la funzione di costruzione viene chiamata per impostazione predefinita. Questa funzione contiene il codice per l'impostazione del contatore e il numero id per quell'istanza dell'oggetto. Quindi, se un oggetto è stato creato per la terza volta, quell'oggetto avrà un id di 3, che è specifico solo per quell'oggetto. Il contatore continuerà a salire mentre più oggetti continuano a essere creati.

Nota che i membri regolari della classe esistono separatamente su ciascun oggetto. Tuttavia, i membri statici esistono solo una volta a livello globale.


7 metodi di classe statica

Non solo i membri, ma anche i metodi di una classe possono essere resi "statici".

 class Foo // nota la parola chiave statica public static function hello () echo "Hello World"; 

E questo è come puoi chiamarli:

 Foo :: ciao (); // stampa Hello World

Nota come la sintassi è simile all'accesso ai membri statici, usando i due punti (:).

All'interno di un metodo statico, una classe può riferirsi a se stessa usando la parola chiave 'self' e accedere ai membri statici in questo modo:

 class Foo public static $ call_me_count = 0; funzione statica pubblica call_me () self :: $ call_me_count ++; echo "Mi hai chiamato" .self :: $ call_me_count. "volte 
\ n "; // output => Mi hai chiamato 1 volte Foo :: call_me (); // output => Mi hai chiamato 2 volte Foo :: call_me (); // output => Mi hai chiamato 3 volte Foo :: call_me (); // output => Mi hai chiamato 4 volte Foo :: call_me ();

8 Il modello Singleton

Un 'Singleton' è una classe che può esistere solo come istanza di un singolo oggetto. Contiene anche un riferimento statico a questa istanza.

Potrebbe essere più chiaro guardando il codice:

 class Foo // per contenere un'istanza di Foo private static $ istanza; // rendere privato il costruttore, quindi non può essere chiamato da una funzione privata esterna __construct ()  // il metodo singleton public static function getInstance () // se l'istanza non esiste ancora, creala if (! isset (self :: $ istanza)) $ c = __CLASS__; self :: $ instance = new $ c;  // restituisce l'unica istanza return self :: $ istanza;  // la clonazione non è consentita public function __clone () trigger_error ('Cloning is not allowed.', E_USER_ERROR); 

Questa è la struttura dello scheletro. Puoi naturalmente aggiungere più metodi e membri, o semplicemente estendere la classe.

Quando chiamiamo il metodo getInstance (), accadono due cose.

 $ var = Foo :: getInstance ();

Innanzitutto, se non ci sono oggetti Foo, uno viene creato e assegnato a Foo :: $ istanza. Quindi, una volta che c'è quell'oggetto, viene restituito, quindi $ var diventa quell'oggetto. Se lo chiami più volte, ogni volta otterrai lo stesso oggetto esatto; non verrà creata una nuova istanza.

 $ var = Foo :: getInstance (); $ var2 = Foo :: getInstance (); // $ var e $ var2 fanno riferimento allo stesso oggetto esatto

Poiché abbiamo reso privato il metodo __construct (), non possiamo creare nuove istanze di questo oggetto.

 // questo genererà un errore $ var = new Foo ();

9 A Singleton CurrentUser Class

Ora è il momento di costruire un esempio più concreto con Singleton Pattern.

Immagina di avere una classe utente con vari metodi:

 class User public $ id; nome $ pubblico; pubblico $ email; public function load_user ($ id) // recupera da db // ... public function update_user ($ info) // aggiorna db con dato $ info array // ... public function comment_count () // calcola il numero di Commenti //…  

Abbiamo un metodo per prelevare un utente dall'ID dal database. Quindi potrebbe essere usato in questo modo:

 $ user = new User (); $ User-> load_user ($ user_id); // ora posso vedere il nome, e altre cose echo $ user-> name; echo $ user-> comment_count ();

Ora immagina che una volta che un utente ha effettuato l'accesso, memorizzi il loro id nella sessione. E la prossima volta che caricano una pagina, devi cercare quell'id e creare nuovamente l'oggetto $ utente correlato per quell'utente, se desideri accedere ai membri e ai metodi di quell'oggetto.

Ma a causa di problemi di ambito variabile, dovrai rendere globale l'oggetto $ user, o continuare a inizializzarlo da diverse funzioni / metodi all'interno del tuo script. Qui è dove una classe singleton può tornare utile:

 class CurrentUser estende l'utente istanza privata statica $; funzione privata __construct () // assicurati di chiamare genitore costruttore genitore :: __ construct ();  public static function getInstance () // initialize if (! isset (self :: $ instance)) // la sessione esiste? if (! $ _ SESSION ['user_id']) return false;  $ c = __CLASS__; self :: $ instance = new $ c; self :: $ esempio-> load_user ($ _ SESSION [ 'user_id']);  return self :: $ istanza;  public function __clone () trigger_error ('Cloning is not allowed.', E_USER_ERROR); 

Ora possiamo accedere alla classe CurrentUser da qualsiasi punto della nostra applicazione:

 $ user = CurrentUser :: getInstance (); if (! $ user) echo "Non hai effettuato l'accesso!";  else echo Bentornato $ user-> nome ";

Quindi, nel nostro codice non abbiamo dovuto preoccuparci di gestire la sessione. Possiamo semplicemente tentare di ottenere l'istanza dell'oggetto CurrentUser e usarla come qualsiasi oggetto User, poiché estende la sua funzionalità.


Conclusione

Spero ti sia piaciuto questo tutorial e ho imparato da esso. Arrivederci alla prossima!