Vrijstaande statische php p. Voorbereiden op een PHP-interview: trefwoord “statisch”

Late Static Binding (LSB) is de afgelopen drie jaar een veelbesproken onderwerp van discussie geweest in PHP-ontwikkelkringen (en we kregen het eindelijk in PHP 5.3). Maar waarom is het nodig? In dit artikel zullen we onderzoeken hoe precies late statische binding kan uw code aanzienlijk vereenvoudigen.

Tijdens een PHP-ontwikkelaarsbijeenkomst in Parijs in november 2005 werd het onderwerp laat-statische koppeling formeel besproken door het kernontwikkelingsteam. Ze kwamen overeen om het uit te voeren, samen met vele andere onderwerpen die op de agenda stonden. Details moesten via open discussies worden overeengekomen.

Sinds late statische binding werd aangekondigd als een komende speelfilm, zijn er twee jaar verstreken. En uiteindelijk werd LSB beschikbaar voor gebruik in PHP 5.3. Maar deze gebeurtenis bleef onopgemerkt door ontwikkelaars die PHP gebruikten; uit de opmerkingen blijkt slechts een pagina in de handleiding.

Kortom, de nieuwe late statische bindingsfunctionaliteit zorgt ervoor dat objecten nog steeds methoden kunnen erven van bovenliggende klassen, maar maakt het bovendien mogelijk dat overgeërfde methoden toegang hebben tot statische constanten, methoden en eigenschappen van de onderliggende klasse, en niet alleen de bovenliggende klasse. Laten we eens kijken naar een voorbeeld:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

klasse Bier (
const NAME = "Bier!" ;

retour zelf :: NAAM ;
}
}
klasse Ale breidt bier uit (
const NAAM = "Ale!" ;
}

$bierDrink = nieuw bier;
$aleDrink = nieuw bier;

echo "Bier is: " .
$beerDrink -> getName () . "\N" ;

echo "Ale is: ".

$aleDrink -> getName() . "\N" ;

Deze code levert het volgende resultaat op:

Bier is: Bier!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

klasse Bier (
const NAME = "Bier!" ;
Bier is: bier!
retour zelf :: NAAM ;
}
De klasse Ale erft de methode getName(), maar self verwijst nog steeds naar de klasse waarin deze wordt gebruikt (in dit geval de klasse Beer). Dit bleef in PHP 5.3, maar het woord statisch werd toegevoegd. Laten we nog eens naar het voorbeeld kijken:
publieke functie getName() (
}
}

klasse Ale breidt bier uit (
const NAAM = "Ale!" ;
}

$bierDrink = nieuw bier;

$aleDrink = nieuw bier;

echo "Bier is: " .
$beerDrink -> getName () . "\N" ;

publieke functie getStaticName() (
retourneer statisch::NAAM ;

echo "Bier is eigenlijk: " .

Intern is het belangrijkste verschil (en in feite de reden waarom binding laat wordt aangeroepen) tussen deze twee toegangsmethoden dat PHP de waarde voor self::NAME zal bepalen tijdens het compileren (wanneer PHP-tekens worden omgezet in machinecode die door de Zend-engine wordt verwerkt), en voor static::NAME wordt de waarde bepaald bij het opstarten (op het moment dat de machinecode wordt uitgevoerd in de Zend-engine).

Dit is een ander hulpmiddel voor PHP-ontwikkelaars. In het tweede deel zullen we bekijken hoe het ten goede kan worden gebruikt.

Vanaf PHP 5.3.0 was er een functie genaamd late statische binding die kan worden gebruikt om een ​​verwijzing naar een opvraagbare klasse te verkrijgen in de context van statische overerving.

Meer specifiek behoudt late statische binding de naam van de klasse die is opgegeven in de laatste "niet-doorgestuurde oproep". Bij statische oproepen is dit een expliciet gespecificeerde klasse (meestal links van de operator :: ); bij niet-statische oproepen is dit de klasse van het object. Een "omgeleid gesprek" is een statisch gesprek dat begint met, zelf::, ouder:: statisch:: ouder::, of, omhoog in de klassenhiërarchie, forward_static_call() .

De functie get_calld_class() kan worden gebruikt om een ​​string op te halen met de naam van de aangeroepen klasse, en ouder:: vertegenwoordigt de reikwijdte ervan.

De naam “late statische binding” weerspiegelt zelf de interne implementatie van deze functie. "Late binding" weerspiegelt het feit dat oproepen doorkomen bij niet-statische oproepen is dit de klasse van het object. Een "omgeleid gesprek" is een statisch gesprek dat begint met

wordt niet berekend ten opzichte van de klasse waarin de aangeroepen methode is gedefinieerd, maar wordt berekend op basis van informatie tijdens runtime. bij niet-statische oproepen is dit de klasse van het object. Een "omgeleid gesprek" is een statisch gesprek dat begint met

Deze functie werd ook wel "statische binding" genoemd omdat deze kan worden gebruikt (maar dat niet hoeft) in statische methoden.

Beperkingen Voorbeeld #1 Gebruik Met behulp van late statische binding Latere statische binding probeert deze beperking te overwinnen door een sleutelwoord op te geven dat verwijst naar een klasse die rechtstreeks tijdens runtime wordt aangeroepen. Simpel gezegd: een trefwoord waarnaar u kunt linken B van test()

in het vorige voorbeeld. Er werd besloten om geen nieuw zoekwoord te introduceren, maar te gebruiken ouder::

statisch

, die al gereserveerd is.

Voorbeeld #2 Gemakkelijk te gebruiken Het resultaat van het uitvoeren van dit voorbeeld: zal proberen privémethoden uit hetzelfde bereik aan te roepen, met behulp van ouder:: kan verschillende resultaten opleveren. ouder:: Een ander verschil is dat

kan alleen verwijzen naar statische velden van een klasse. ouder:: Voorbeeld #3 Gebruik

statisch

in een niet-statische context

, die al gereserveerd is.

succes! succes! succes! Fatale fout: oproep naar privémethode C::foo() vanuit context "A" in /tmp/test.php op regel 9 zelf:: Het oplossende gebied van late statische binding zal worden vastgesteld door de statische aanroep die het berekent. Aan de andere kant kunnen statische oproepen met behulp van richtlijnen zoals bij niet-statische oproepen is dit de klasse van het object. Een "omgeleid gesprek" is een statisch gesprek dat begint met of

oproepinformatie omleiden.

  • Voorbeeld #4 Omgeleide en niet-omgeleide oproepen
  • Programmering,
    • OOP

    Handleiding

    Het is geen geheim dat mensen tijdens sollicitatiegesprekken graag lastige vragen stellen. Niet altijd adequaat, niet altijd gerelateerd aan de realiteit, maar het feit blijft een feit - vragen ze. Natuurlijk is de vraag anders, en soms is een vraag die je op het eerste gezicht stom lijkt, eigenlijk bedoeld om te testen hoe goed je de taal kent waarin je schrijft.

    Laten we proberen een van deze vragen te ontrafelen: wat betekent het woord 'statisch' in PHP en waarom wordt het gebruikt?

    Het statische trefwoord heeft drie verschillende betekenissen in PHP. Laten we ze in chronologische volgorde bekijken, zoals ze in de taal verschenen.

    De eerste waarde is een statische lokale variabelefunctie foo() ( $a = 0; echo $a; $a = $a + 1; ) foo(); // 0 foo(); // 0 foo(); // 0

    In PHP zijn variabelen lokaal. Dit betekent dat een variabele die binnen een functie (methode) is gedefinieerd en een waarde heeft gekregen, alleen bestaat tijdens de uitvoering van die functie (methode). Wanneer de methode wordt afgesloten, wordt de lokale variabele vernietigd, en wanneer deze opnieuw binnenkomt, wordt deze opnieuw gemaakt. In de bovenstaande code is zo'n lokale variabele de variabele $a. Deze bestaat alleen binnen de functie foo() en wordt elke keer dat deze functie wordt aangeroepen opnieuw gemaakt. Het verhogen van een variabele in deze code heeft geen zin, omdat de functie op de volgende regel code zijn werk zal beëindigen en de waarde van de variabele verloren zal gaan. Ongeacht hoe vaak we de functie foo() aanroepen, deze zal altijd 0 opleveren...

    Alles verandert echter als we het statische trefwoord vóór de opdracht plaatsen:

    Functie foo() ( statisch $a = 0; echo $a; $a = $a + 1; ) foo(); // 0 foo(); // 1 foo(); // 2

  • Het statische trefwoord, geschreven vóór het toekennen van een waarde aan een lokale variabele, heeft de volgende effecten:
  • De waarde van een op deze manier gemarkeerde variabele wordt opgeslagen nadat de functie is beëindigd.
  • Bij volgende aanroepen van de functie ontvangt de variabele, in plaats van toewijzing, de eerder opgeslagen waarde
  • Dit gebruik van het woord statisch wordt een statische lokale variabele genoemd. Valkuilen van statische variabelen Natuurlijk zijn er, zoals altijd in PHP, enkele valkuilen.

    De eerste steen is dat alleen constanten of constante-uitdrukkingen kunnen worden toegewezen aan een statische variabele.
    Hier is de code:
    statisch $a = balk();

    onvermijdelijk tot een parserfout leiden. Gelukkig is het vanaf versie 5.6 mogelijk geworden om niet alleen constanten toe te wijzen, maar ook constante-expressies (bijvoorbeeld “1+2” of “”), dat wil zeggen expressies die niet afhankelijk zijn van andere code en kunnen worden berekend in de compilatiefase
    De tweede steen is dat methoden in één enkele kopie bestaan.
    Hier is alles een beetje ingewikkelder. Om de essentie te begrijpen, is hier de code:
    klasse A ( publieke functie foo() ( static $x = 0; echo ++$x; ) ) $a1 = new A; $a2 = nieuwe A; $a1->foo(); // 1 $a2->foo(); // 2 $a1->foo(); // 3 $a2->foo(); // 4

    In tegenstelling tot de intuïtieve verwachting ‘verschillende objecten - verschillende methoden’ zien we in dit voorbeeld duidelijk dat dynamische methoden in PHP ‘niet vermenigvuldigen’. Zelfs als we honderd objecten van deze klasse hebben, zal de methode slechts in één exemplaar bestaan; het is alleen zo dat er bij elke aanroep een andere $this in wordt gegooid.

    Dit gedrag kan onverwacht zijn voor een ontwikkelaar die er niet op is voorbereid en kan een bron van fouten zijn. Opgemerkt moet worden dat klasse- (en methode-)overerving leidt tot het creëren van een nieuwe methode:

    Klasse A ( publieke functie foo() ( static $x = 0; echo ++$x; ) ) klasse B breidt A uit ( ) $a1 = new A; $b1 = nieuwe B; $a1->foo(); // 1 $b1->foo(); // 1 $a1->foo(); // 2 $b1->foo(); // 2

    Conclusie: Dynamische methoden in PHP bestaan ​​in de context van klassen, niet in objecten. En alleen tijdens runtime vindt de vervanging “$this = current_object” plaats

    De tweede betekenis is statische eigenschappen en methoden van klassen. In het PHP-objectmodel is het mogelijk om niet alleen eigenschappen en methoden in te stellen voor objecten (instanties van een klasse), maar ook voor de klasse als geheel. Hiervoor wordt ook het statische zoekwoord gebruikt:
    Klasse A ( public static $x = "foo"; public static function test() ( return 42; ) ) echo A::$x; // "foo" echo A::test(); // 42

    Het spreekt voor zich dat statische eigenschappen en statische methoden hun eigen kenmerken en valkuilen hebben die u moet kennen.

    Het eerste kenmerk is banaal: er is geen $this.

    Eigenlijk komt dit voort uit de definitie van een statische methode. Omdat deze geassocieerd is met een klasse en niet met een object, is de pseudovariabele $this, die in dynamische methoden naar het huidige object verwijst, niet beschikbaar. Wat volkomen logisch is.

    U moet echter weten dat PHP, in tegenstelling tot andere talen, de situatie “$this is geschreven in een statische methode” niet detecteert tijdens het parseren of compileren. Een dergelijke fout kan alleen optreden tijdens runtime als u code probeert uit te voeren met $this binnen een statische methode.
    Codeer als volgt:
    klasse A ( public $id = 42; statische publieke functie foo() ( echo $this->id; ) )
    zal geen fouten veroorzaken, zolang je de methode foo() niet op ongepaste wijze gebruikt:

    $a = nieuwe A; $a->foo();
    (en krijg onmiddellijk "Fatale fout: gebruik $this wanneer niet in objectcontext")
    Het tweede kenmerk is dat statisch geen axioma is!

    klasse A ( statische publieke functie foo() ( echo 42; ) ) $a = new A; $a->foo();
    Dat is het, ja. Een statische methode kan, als deze niet $this in de code bevat, in een dynamische context worden aangeroepen, zoals een objectmethode. Dit is geen bug in PHP.
    Het omgekeerde is niet helemaal waar:

    klasse A ( publieke functie foo() ( echo 42; ) ) A::foo();

    Een dynamische methode die $this niet gebruikt, kan in een statische context worden uitgevoerd. U ontvangt echter een waarschuwing "Niet-statische methode A::foo() mag niet statisch worden aangeroepen" op niveau E_STRICT. Het is aan u om te beslissen of u de codestandaarden strikt volgt of waarschuwingen onderdrukt. Het eerste verdient uiteraard de voorkeur.

    En trouwens, alles wat hierboven is geschreven, is alleen van toepassing op methoden. Het gebruik van een statische eigenschap via "->" is onmogelijk en leidt tot een fatale fout.

    De derde betekenis, die het meest complex lijkt te zijn: late statische binding. De ontwikkelaars van de PHP-taal stopten niet bij twee betekenissen van het trefwoord “statisch” en in versie 5.3 voegden ze nog een “kenmerk” van de taal toe, die is geïmplementeerd met hetzelfde woord! Het heet "late statische binding" of LSB (Late Static Binding).
    Het trefwoord self in PHP betekent altijd ‘de naam van de klasse waarin dit woord is geschreven’. In dit geval wordt self vervangen door de klasse Model, en self::$table door Model::$table.
    Deze taalfunctie wordt "vroege statische binding" genoemd. Waarom vroeg? Omdat de binding van zichzelf en een specifieke klassenaam niet tijdens runtime plaatsvindt, maar in eerdere fasen: het parseren en compileren van de code. Nou ja, “statisch” - omdat we het hebben over statische eigenschappen en methoden.

    Laten we onze code een beetje veranderen:

    Klassemodel ( public static $table = "table"; public static function getTable() ( return self::$table; ) ) class User breidt Model uit ( public static $table = "users"; ) echo User::getTable() ; // "tafel"

    Nu begrijp je waarom PHP zich in deze situatie niet intuïtief gedraagt. self werd geassocieerd met de klasse Model toen er nog niets bekend was over de klasse User, en verwijst daarom naar Model.

    Wat moet ik doen?

    Om dit dilemma op te lossen werd in de runtime-fase een ‘laat’ bindingsmechanisme uitgevonden. Het werkt heel eenvoudig: schrijf gewoon ‘statisch’ in plaats van het woord ‘self’ en er wordt verbinding gemaakt met de klasse die deze code aanroept, en niet met degene waar deze is geschreven:
    class Model ( public static $table = "table"; public static function getTable() ( return static::$table; ) ) class User breidt Model uit ( public static $table = "users"; ) echo User::getTable() ; // "gebruikers"

    Dit is de mysterieuze ‘late statische binding’.

    Opgemerkt moet worden dat er voor meer gemak in PHP, naast het woord "statisch", ook een speciale functie get_call_class() is, die u zal vertellen in de context van welke klasse uw code momenteel werkt.

    Fijne sollicitatiegesprekken!



    Er zijn twee soorten PHP-ontwikkelaars in de wereld. Sommigen geven de voorkeur aan statische methoden omdat ze gemakkelijk zijn om mee te werken, terwijl anderen statische methoden daarentegen als slecht beschouwen en ze niet in hun praktijk gebruiken.
    In dit artikel zal ik proberen, gebruikmakend van mijn ervaring met het werken met verschillende frameworks, uit te leggen waarom sommige ontwikkelaars best practices negeren en een hele reeks statische methoden gebruiken. Wie houdt er van statische methoden? CodeIgniter-framework in hun werk.

    Bovendien zijn de meeste Kohana- en Laravel-ontwikkelaars aanhangers van statistische methoden.
    Hier kunnen we niet anders dan vermelden dat programmeurs die besluiten hun eigen dingen te gaan schrijven, meestal weigeren CodeIgniter te gebruiken.

    Waarom, vraag je?

    CodeIgniter ondersteunde PHP 4 voordat statische methoden werden toegevoegd in PHP 5. Bovendien gebruikt CodeIgniter een "superobject" dat gelijke toegang geeft tot alle klassen die aan de controller zijn toegewezen. Zo komen ze beschikbaar voor gebruik in het hele systeem.

    Dit betekent dat klassen toegankelijk zijn vanuit elk model met behulp van de methode __get(), die de gevraagde eigenschap opzoekt met behulp van get_instance()->($var). Voorheen, toen de functie __get() niet werd ondersteund in PHP 4, werd dit gedaan met behulp van een foreach-constructie via de CI_Controller-parameters en deze vervolgens toe te wijzen aan de $this-variabele in het model.

    In de bibliotheek moet je get_instance aanroepen. De bibliotheek dwingt geen klassenovererving af, dus er is geen manier om de functie __get() te omzeilen.

    Volume... Het blijkt een nogal omslachtige structuur te zijn om toegang te krijgen tot de code. Exact dezelfde functionaliteit kan zonder extra inspanning worden bereikt met een statische methode.

    En het heeft geen enkel nut om een ​​dergelijk ontwerp te bespreken. Oké, u heeft toegang tot de sessiegegevens in uw model. Maar waarom zou je dit doen?

    "De oplossing" De Kohana-ontwikkelaars waren de eersten die serieus aan statische methoden werkten. Ze hebben de volgende wijzigingen aangebracht:
    //was $this->invoer->get("foo");
    // werd Input::get("foo");

    Voor veel CodeIgniter-ontwikkelaars met verouderde PHP 4 die naar het Kohana-framework zijn overgestapt om te profiteren van alle voordelen van PHP 5, is dit niets ongewoons. Maar hoe minder karakters, hoe beter, toch? Dus wat is het probleem? Veel PHP-ontwikkelaars (vooral degenen die goed thuis zijn in Symfony en Zend) zullen zeggen: "Het is duidelijk: gebruik Dependency Injection!" Maar niet veel ontwikkelaars in de CodeIgniter-gemeenschap hebben echte ervaring met dit proces, omdat het behoorlijk complex is.

    Een ander feit over het Fuel PHP-framework is dat tot nu toe vooral statische methoden als interface fungeren. Logica heeft bijvoorbeeld nog steeds problemen met statica, vooral als het om het HMVC-concept gaat.
    Dit is pseudocode die ik sinds versie 1.1 niet meer in FuelPHP heb gebruikt:
    klasse ControllerA breidt Controller uit ( public function action_foo() ( echo Input::get("param"); ​​​) ) Vrij standaardcode. Deze methode zal de waarde uitvoeren?bar=

    in de methode.
    klasse ControllerB breidt Controller uit ( public function action_baz() ( echo Input::get("param"); ​​echo " & "; echo Request::forge("controllera/foo?param=val1")->execute() ;)
    Door in de browser te bellen controllerb/baz, ziet u de uitvoer "val1", maar als u typt controllerb/baz?param=overschrijven en haal vervolgens beide aanroepen op om ervoor te zorgen dat de methode dezelfde waarde retourneert.

    Relevantie De globale code geeft u geen enkele relevantie. Een voorbeeld is beter dan welk woord dan ook:
    $dit->verzoek->invoer->get("param");
    Het opgevraagde object zal voor ieder verzoek een geheel nieuw exemplaar bevatten, waarna voor elk verzoek een invoerobject wordt aangemaakt dat alleen de invoergegevens voor het specifieke verzoek bevat. Dit geldt voor de plannen van FuelPHP 2.0 om te werken en lost het probleem van Dependency Injection op, evenals problemen met HMVC. Hoe zit het met de ruwe syntaxis? Symfony- of Zend-ontwikkelaars hebben hier geen last van, maar degenen die CodeIgniter gebruiken, zullen nachtmerries hebben over 'terugkeren' naar PHP4."

    $this verwijst altijd naar het "huidige" object, en je zou het zeker niet moeten gebruiken om toegang te krijgen tot globale code.

    $this->request->input->get() lijkt misschien op een lange vorm van CodeIgniter-syntaxis, maar we zitten eigenlijk gewoon in een controller. Wanneer de controller een nieuwe query genereert die erin is genest, ontvangt de queryconstructor ook een instance als invoer.

    Als je in een model of een andere klasse zit, zal toegang zoals $this->request->input->foo() niet werken omdat $this geen controller is.

    De constructie Input::get("foo") creëert een façade voor logische instanties op de achtergrond. Maar dit lost de problemen die verband houden met de werking van de mondiale code niet op. De meest luie mensen bij het testen van applicaties kunnen tussen de twee modi schakelen zonder een volledig nieuw raamwerk te hoeven gebruiken.

    Er is een geweldige video van Taylor Otwell (maker van laravel 4) waarin hij beschrijft hoe je statische code kunt vervangen door een enkele instantie die via zijn DiC-container is getest.

    Laravel 4 - IoC-controllerinjectie en unittesten van UserScape op Vimeo.

    Dit is een geweldige presentatie van hoe je weg kunt komen zonder statische methoden te gebruiken in Laravel. Hoewel sommige moderne raamwerken op het eerste gezicht erg op Kohana lijken, lossen ze zelfs de meest standaardproblemen op totaal verschillende manieren op.

    Even een trieste opmerking: ik ben momenteel bezig met het converteren van PyroCMS van CodeIgniter naar Laravel. Proberen om rechtstreeks van de mondiale PHP 4-code naar een perfecte afhankelijkheidsinjectie te gaan, is absolute zelfmoord. Een tussenstap voordat u de CI-lader gebruikt, is het gebruik van PHP 5, PSR-2 autoloading-code met een aantal statische methoden. Nou, voorlopig zitten we nog steeds in CodeIgniter.

    De overgang van statische naar DiC-code kan eenvoudig worden gedemonstreerd als we eindelijk de overstap naar Laravel maken.

    De overstap van nauw gekoppelde CodeIgniter-code naar testbare PSR-2 is een grote uitdaging. Het Pyro-team is onderweg – en het wordt episch.

    Een zeer belangrijk kenmerk van OOP is de aanwezigheid van statische eigenschappen en methoden. Het belangrijkste is dat je meteen moet begrijpen dat dergelijke eigenschappen en methoden niet tot het object behoren, maar tot de klasse. Dit moet vanaf het allereerste begin worden begrepen, maar ik zal in dit artikel kijken naar het gebruik van statische eigenschappen en methoden in PHP.

    Het meest klassieke voorbeeld is een klasse die verantwoordelijk is voor wiskundige functies. Als iemand Java kent, dan weet hij dat er een klasse Math bestaat (JavaScript heeft ook zo'n klasse), die veel wiskundige functies bevat. En hun methoden zijn statisch. Dit betekent dat u, om een ​​sinus of exponent te berekenen, geen object van deze klasse hoeft te maken, wat erg handig is.

    Laten we een kleinere kopie van deze klasse schrijven, maar alleen voor PHP:

    In deze code liet ik het gebruik van statische methoden en eigenschappen zien. Houd er rekening mee dat ik de klassieke objecttellermethode heb geïmplementeerd. Dit gebeurde alleen omdat het telveld statisch is en voor alle objecten dezelfde waarde heeft.

    Een ander populair voorbeeld van het gebruik van statische methoden en eigenschappen is logboekregistratie. Alle vermeldingen worden via statische methoden toegevoegd. Het is ook heel gebruikelijk om een ​​klasse te maken die uit veel instellingen bestaat, en ook daar zijn alle velden statisch. Zoals je ziet zijn er meer dan genoeg voorbeelden van het gebruik van statische methoden en eigenschappen in PHP en andere talen, dus het is absoluut noodzakelijk om ermee te kunnen werken.