Alles over het 'statische' sleutelwoord

Vandaag gaan we leren om het 'static' keyword in PHP te gebruiken. We gaan de basis verder en bouwen enkele voorbeelden. Het is tijd om deze interessante taalfunctie toe te voegen aan uw webontwikkelingstas met trucs.


1 Een snel voorbeeld

Laten we eerst een snel voorbeeld nemen om het effect te zien van het gebruik van het statische sleutelwoord.

Stel je voor dat je een functie schrijft die onthoudt hoe vaak het totaal is genoemd. Als u niet vertrouwd bent met het 'statische' sleutelwoord, kunt u een globale variabele gebruiken:

 $ call_me_count = 0; functie call_me () global $ call_me_count; $ Call_me_count ++; echo "Je hebt me $ call_me_count keer genoemd 
\ n "; // output => Je belde me 1 keer call_me (); // output => Je belde me 2 keer call_me (); // output => Je belde me 3 keer call_me (); // output => Je hebt me 4 keer call_me () genoemd;

Gewoon omdat dit werkt, betekent niet dat je code op deze manier moet schrijven. Over het algemeen worden globale variabelen afgekeurd. Het is geen goed idee om globale variabelen rond te laten zweven, dat sommige functies alleen privé worden gebruikt.

Voer nu het 'statische' sleutelwoord in. Dezelfde code kan als volgt worden herschreven:

 functie call_me () // een statische variabele static $ call_me_count = 0; $ Call_me_count ++; echo "Je hebt me $ call_me_count keer genoemd 
\ n "; // output => Je belde me 1 keer call_me (); // output => Je belde me 2 keer call_me (); // output => Je belde me 3 keer call_me (); // output => Je hebt me 4 keer call_me () genoemd;

Hetzelfde resultaat, geen globalere variabelen meer. Maar hoe werkt dit precies?

Normaal gesproken worden alle lokale variabelen binnen een functie vernietigd zodra de functie terugkeert. Met de 'statische' sleutelwoorden weet PHP de variabele in leven te houden. Dus de volgende keer dat de functie wordt aangeroepen, blijft de waarde binnen de variabele behouden.


2 Geldige beginwaarden

Zoals we in het vorige voorbeeld hebben gezien, toen we de waarde van 0 aan de variabele hebben toegewezen, heeft deze in feite geen toewijzingsinstructie uitgevoerd. Het stelde alleen de beginwaarde voor de variabele in. Dat klinkt misschien hetzelfde, maar er is een klein verschil. De variabele kan alleen worden geïnitialiseerd naar een vaste waarde en niet naar een expressie.

Laten we enkele voorbeelden van geldige en ongeldige beginwaarden bekijken. Laten we eerst naar cijfers kijken:

 function foo () // geldige statische $ a = 9; // veroorzaakt parse error static $ a = sqrt (81); // geldige statische $ a = 3.14; // veroorzaakt parse error static $ a = pi (); // veroorzaakt parse error static $ a = 1 + 3; 

Zoals je kunt zien, zijn zelfs basale wiskundige bewerkingen niet toegestaan. Het enige dat u kunt toewijzen, is vaste nummers.

We kunnen ook strings toewijzen:

 function foo () // geldige statische $ a = "; // geldige statische $ a = 'hallo'; // veroorzaakt parse error static $ a = strtoupper ('hallo'); // veroorzaakt parse error static $ a = 'Hallo Wereld'; 

Nogmaals, het moeten vaste reeksen zijn, en zelfs basale aaneenschakeling is niet toegestaan.

Booleans, Arrays en Constants zullen ook werken:

 define ("SOME_CONSTANT", 789); function foo () // geldige statische $ a = array (1,2,3); // geldige statische $ a = SOME_CONSTANT; // geldige statische $ a = array (1,2, 'three', array ('foo' => 'bar')); // geldige statische $ a = true; 

3 Een alternatieve functie () bouwen

Nu we weten hoe statische variabelen binnen functies werken, laten we er iets nuttigs mee bouwen.

Hier is een eenvoudige HTML-pagina met daarin een eenvoudige tabel:

    Mijn tafel    
ID kaart Naam Categorie
1 appel Fruit
2 Wortel Groente
3 Hond Dier
4 Oven toestel

Het resultaat is:


Laten we nu wat CSS toevoegen en de rijen afwisselend van kleur maken:

    Mijn tafel     
ID kaart Naam Categorie
1 appel Fruit
2 Wortel Groente
3 Hond Dier
4 Oven toestel

Nu ziet het er zo uit:


Als de gegevens afkomstig waren uit een database en de tabelrijen werden uitgevoerd binnen een lus, zou u een aantal code moeten toevoegen om die alternerende CSS-klassen in te stellen voor elke rij. De meeste mensen gaan gewoon door en maken een variabele binnen die lus, voegen een voorwaardelijke of drievoudige instructie toe om de waarde afwisselend te houden.

We gaan echter een elegantere en herbruikbare oplossing bouwen. We gaan een functie met de naam alternate () maken die het concept van statische variabelen gebruikt.

 functie alternatief ($ a, $ b) statisch $ alt = false; // keer de waarde van alt om (waar <=> false) $ alt =! $ alt; if ($ alt) return $ a; // retourneer eerste waarde else return $ b; // retourneer tweede waarde // Voorbeeld Gebruik: // uitvoer: oneven echo alternerend ('oneven', 'even'); // output: even echo alternerend ('odd', 'even'); // output: oneven echo alternerend ('oneven', 'even');

We noemen de functie met twee argumenten. Telkens als het wordt aangeroepen, retourneert het een van de argumenten op een afwisselende manier. Dit wordt bereikt door een Booleaanse waarde te behouden in een statische variabele met de naam $ alt. Telkens wanneer deze waarde van deze variabele wordt omgezet, wordt bepaald welke van de twee argumenten moet worden geretourneerd.

Dus laten we dat op onze pagina gebruiken, door het allemaal samen te voegen:

  false) $ alt =! $ alt; if ($ alt) return $ a; // retourneer eerste waarde else return $ b; // tweede waarde teruggeven $ rijen = array (array (1, 'Apple', 'Fruit'), array (2, 'Carrot', 'Vegetable'), array (3, 'Dog', 'Animal') , array (4, 'Oven', 'Appliance')); ?>    Mijn tafel     
ID kaart Naam Categorie
', $ rij); ?>

En het uiteindelijke resultaat is hetzelfde:



4 Onze alternatieve functie () verbeteren

De functie die we hebben gemaakt, werkt goed, als we deze slechts op één plek in onze scripts gebruiken. Er is echter een klein probleem mee. Als we het op meerdere plaatsen gebruiken of in geneste lussen, retourneren we de waarden mogelijk niet in de volgorde die we van plan waren. Laten we deze code bekijken om dit probleem te demonstreren:

 // een echo alternatief ('a', 'b'). "
\ n "; // b echo alternate ('a', 'b')."
\ n "; // een alternatieve echo ('a', 'b')."
\ n "; // even // (de tweede waarde wordt eerst geretourneerd!) echo alternate ('odd', 'even')."
\ n "; // oneven echo alternerend ('odd', 'even')."
\ n "; // bar // (zelfde probleem) echo alternate ('foo', 'bar')."
\ n "; // a // (laatste keer was het ook 'a') echo alternerend ('a', 'b')."
\ N ";

Onze functie moet zich ervan bewust zijn dat deze op verschillende plaatsen wordt aangeroepen en zorg ervoor dat de waarden dienovereenkomstig worden geretourneerd. We kunnen dit bereiken door een optionele laatste parameter toe te voegen, om een ​​ID-nummer toe te wijzen. En we geven een unieke ID door van elke andere plaats waar we het vandaan halen, om deze conflicten te voorkomen:

 function alternate ($ a, $ b, $ id = 0) static $ alt = array (); if (! isset ($ alt [$ id])) $ alt [$ id] = false;  $ alt [$ id] =! $ alt [$ id]; if ($ alt [$ id]) return $ a;  else return $ b;  // een alternatieve echo ('a', 'b', 1). "
\ n "; // b echo alternate ('a', 'b', 1)."
\ n "; // een alternatieve echo ('a', 'b', 1)."
\ n "; // oneven echo alternerend ('odd', 'even', 2)."
\ n "; // even echo alternerend ('odd', 'even', 2)."
\ n "; // foo echo alternate ('foo', 'bar', 3)."
\ n "; // b echo alternate ('a', 'b', 1)."
\ N ";

Deze keer gebruiken we een array als een statische variabele. Het draagt ​​een unieke Booleaanse waarde voor elk verschillend ID-nummer dat is doorgegeven. Hierdoor kan het de waarden in de juiste volgorde retourneren.


5 leden van de statische klasse

Het 'statische' sleutelwoord wordt niet alleen in functies gebruikt. Het is eigenlijk vrij gebruikelijk in objectgeoriënteerd programmeren. Er kunnen statische leden zijn en methoden. Eerst gaan we kijken hoe statische leden werken.

Hier is de syntaxis:

 class Foo // een statisch lid public static $ a = 0; // een normaal lid publiek $ b = 0; openbare functiebalk () / / toegang tot het statische lid zelf :: $ a; zelf :: $ a ++; zelf :: $ a = 3; // normaal lid: $ this-> b; $ This-> b ++; $ this-> b = 3;  // toegang tot het statische lid // van buiten Foo :: $ a; Foo :: $ a ++; Foo :: $ a = 3; $ obj = nieuwe Foo (); // toegang tot het normale lid $ obj-> b; $ Obj-> b ++; $ obj-> b = 3;

Merk op hoe we het sleutelwoord 'self ::' voor de statische variabele gebruikten om het binnen de klasse te benaderen in plaats van '$ this'. Als we de buitenste scope gebruiken, hoeven we ook geen instantie van het object te maken voordat we toegang hebben tot de statische variabelen. Normale klassenleden kunnen echter alleen worden geopend nadat we een instantie van deze leden hebben gemaakt.


6 Een klasse die zichzelf telt

Herinner je ons eerste voorbeeld waar we een functie hadden die bleef tellen hoe vaak hij werd genoemd? Laten we nu hetzelfde principe toepassen op objectgeoriënteerd programmeren.

Deze klasse heeft de mogelijkheid om te tellen hoeveel keer het totaal is gemaakt:

 class Foo // onze instantie counter public static $ counter = 0; // om te werken als een auto-identificatie ID public $ id = 0; // de constructorfunctie public function __construct () // increment counter self :: $ counter ++; // sla hetzelfde nummer op // als de id van dit object $ this-> id = self :: $ counter;  // output: 0 echo Foo :: $ -teller. "\ N
"; $ a = nieuwe Foo (); // output: 1 echo Foo :: $ counter." \ n
"; $ b = nieuwe Foo (); // output: 2 echo Foo :: $ counter." \ n
"; $ c = nieuwe Foo (); // output: 3 echo Foo :: $ counter." \ n
"; // output: 2 echo $ b-> id;

Telkens wanneer een nieuw object wordt gemaakt, wordt de constructorfunctie standaard aangeroepen. Deze functie bevat code voor het instellen van de teller en het id-nummer voor die instantie van het object. Dus als een object voor de derde keer is gemaakt, heeft dat object een id van 3, die alleen specifiek is voor dat object. De teller blijft omhoog gaan naarmate er meer objecten worden gemaakt.

Merk op dat de reguliere klasleden apart op elk object bestaan. De statische leden bestaan ​​echter slechts eenmaal wereldwijd.


7 Statische klassemethoden

Niet alleen leden, maar ook methoden van een klasse kunnen 'statisch' worden gemaakt.

 class Foo // noteer het statische sleutelwoord public static function hallo () echo "Hello World"; 

En zo kun je ze bellen:

 Foo :: hello (); // print Hello World

Merk op hoe de syntaxis vergelijkbaar is met het benaderen van statische leden, door dubbele dubbele punt (: :) te gebruiken.

Binnen een statische methode kan een klasse naar zichzelf verwijzen met behulp van het sleutelwoord 'zelf' en op deze manier toegang krijgen tot statische leden:

 class Foo public static $ call_me_count = 0; openbare statische functie call_me () self :: $ call_me_count ++; echo "You called me" .self :: $ call_me_count. "times 
\ n "; // output => Je belde me 1 keer Foo :: call_me (); // output => Je belde me 2 keer Foo :: call_me (); // output => Je hebt me 3 keer gebeld Foo :: call_me (); // output => Je hebt me 4 keer Foo :: call_me () genoemd;

8 Het Singleton-patroon

Een 'Singleton' is een klasse die alleen als één objectinstantie kan bestaan. Het bevat ook een statische verwijzing naar dit exemplaar.

Het wordt misschien duidelijker door naar de code te kijken:

 class Foo // om een ​​exemplaar van Foo private static $ instance te bevatten; // constructor privé maken, zodat deze niet van buitenaf privéfunctie kan worden aangeroepen __construct ()  // de singleton-methode public static function getInstance () // als het exemplaar nog niet bestaat, maakt u het als (! isset (self :: $ instance)) $ c = __CLASS__; self :: $ instance = new $ c;  // retourneer de enige instantie retour zelf :: $ instantie;  // klonen is niet toegestaan ​​openbare functie __clone () trigger_error ('Klonen is niet toegestaan.', E_USER_ERROR); 

Dit is de skeletstructuur. Je kunt natuurlijk meer methoden en leden toevoegen, of gewoon de klas uitbreiden.

Wanneer we de methode getInstance () aanroepen, gebeuren er twee dingen.

 $ var = Foo :: getInstance ();

Ten eerste, als er geen Foo-object is, wordt er een gemaakt en toegewezen aan Foo :: $ instance. Dan, zodra er dat object is, wordt het geretourneerd, dus $ var wordt dat object. Als je het meerdere keren noemt, krijg je telkens hetzelfde exacte object; een nieuw exemplaar wordt niet gemaakt.

 $ var = Foo :: getInstance (); $ var2 = Foo :: getInstance (); // $ var en $ var2 verwijzen naar hetzelfde exacte object

Omdat we de methode __construct () privé hebben gemaakt, kunnen we geen nieuwe exemplaren van dit object maken.

 // dit zal een fout veroorzaken $ var = new Foo ();

9 A Singleton CurrentUser Class

Nu is het tijd om een ​​concreter exemplaar te bouwen met het Singleton-patroon.

Stel je voor dat je een gebruikersklasse hebt met verschillende methoden:

 class Gebruiker public $ id; openbare $ naam; public $ email; openbare functie load_user ($ id) // fetch from db // ... public function update_user ($ info) // update db met gegeven $ info array // ... public function comment_count () // bereken het aantal opmerkingen // ...

We hebben één methode voor het ophalen van een gebruiker op id uit de database. Dus het zou als volgt kunnen worden gebruikt:

 $ user = new User (); $ Gebruiksvriendelijkheid> load_user ($ user_id); // nu kan ik de naam zien, en andere dingen echo $ user-> naam; echo $ user-> comment_count ();

Stel je nu voor dat zodra een gebruiker is ingelogd, je zijn ID in de sessie opslaat. En de volgende keer dat ze een pagina laden, moet u die id opzoeken en het bijbehorende $ user-object voor die gebruiker opnieuw maken, als u toegang wilt tot de leden en methoden van dat object.

Maar vanwege problemen met het variabele bereik, moet u ofwel het $ user-object globaal maken, of het blijven initialiseren vanuit verschillende functies / methoden in uw script. Hier is waar een singleton-klasse van pas kan komen:

 class CurrentUser breidt User private static $ instance uit; persoonlijke functie __construct () // zorg ervoor dat de parent constructor parent wordt genoemd: __ construct ();  public static function getInstance () // initialize if (! isset (self :: $ instance)) // bestaat sessie? if (! $ _ SESSION ['user_id']) return false;  $ c = __CLASS__; self :: $ instance = new $ c; zelf :: $ instance-> load_user ($ _ SESSION [ 'user_id']);  return self :: $ instance;  public function __clone () trigger_error ('Klonen is niet toegestaan.', E_USER_ERROR); 

Nu hebben we overal in onze applicatie toegang tot de CurrentUser-klasse:

 $ user = CurrentUser :: getInstance (); if (! $ user) echo "U bent niet aangemeld!";  else echo Welkom terug $ user-> name ";

In onze code hoefden we ons dus geen zorgen te maken over het omgaan met de sessie. We kunnen eenvoudig proberen om het exemplaar van het CurrentUser-object te krijgen en het te gebruiken net als elk gebruikersobject, omdat het de functionaliteit ervan uitbreidt.


Conclusie

Ik hoop dat je deze tutorial leuk vond en ervan hebt geleerd. Tot de volgende keer!