PHP Late Static bindingen

PHP Late Static bindingen

Late Static Bindingen

Vanaf PHP 5.3.0, PHP implementeert een functie genaamd late statische bindingen die kunnen worden gebruikt om de zogenaamde klasse verwijzing in een context van statische erfenis.

Meer in het bijzonder, laat statische banden werken door de opslag van de klasse met de naam in de laatste "non-forwarding call". Bij statische methode oproepen, dit is de klasse expliciet genoemd (meestal op de linkerzijde van de :: operator); in geval van het statische methode oproepen, is de klasse van het object. EEN "forwarding oproep" is statisch die wordt geïntroduceerd door zelf ::. ouder::. statisch::. of, indien het uitgaan in de klasse hiërarchie, forward_static_call (). De functie get_called_class () kan worden gebruikt om een ​​string met de naam van de klasse genoemd en statische ophalen :: introduceert zijn toepassingsgebied.

Deze functie werd genoemd "laat statische bindingen" met een interne perspectief in het achterhoofd. "late binding" komt van het feit dat statische :: niet wordt opgelost met de klasse waarin de werkwijze wordt gedefinieerd, maar het zal eerder berekend met behulp runtime informatie. Het werd ook genoemd een "static binding" als het kan worden gebruikt (maar niet uitsluitend) statische methode aanroept.

Beperkingen van het zelf ::

Statische verwijzingen naar de huidige klasse als zelf :: of __CLASS__ worden opgelost met behulp van de klasse waarin de functie behoort, zoals in waar het werd gedefinieerd:

lt;? php
klasse A, eerste klasse lt;
public static functie die () lt;
echo __CLASS__;
gt;
public static functietest () lt;
zelf. wie ();
gt;
gt;

klasse B breidt A lt;
public static functie die () lt;
echo __CLASS__;
gt;
gt;

Het bovenstaande voorbeeld zal output:

Late Static Bindingen ‘gebruik

Late statische bindingen probeert deze beperking op te lossen door de invoering van een zoekwoord dat de klasse die in eerste instantie werd genoemd tijdens runtime gevonden. Kortom, een sleutelwoord dat laat je toe om B verwijzen uit-test () in het vorige voorbeeld. Er werd besloten een nieuw zoekwoord in te voeren, maar het gebruik van statische die al was gereserveerd.

lt;? php
klasse A, eerste klasse lt;
public static functie die () lt;
echo __CLASS__;
gt;
public static functietest () lt;
statisch. wie (); // Hier komt Late Static bindingen
gt;
gt;

klasse B breidt A lt;
public static functie die () lt;
echo __CLASS__;
gt;
gt;

Het bovenstaande voorbeeld zal output:

In niet-statische context, wordt de opgeroepen klasse de klasse van de objectinstantie zijn. Aangezien $ this-gt; zal proberen om private methoden bellen van dezelfde omvang, gebruik van statische :: kunnen verschillende resultaten geven. Een ander verschil is dat statisch :: kan alleen maar verwijzen naar statische eigenschappen.

Voorbeeld # 3 statische :: gebruik in een niet-statische context

lt;? php
klasse A, eerste klasse lt;
private function foo () lt;
echo "succes! \ n" ;
gt;
publieke functie-test () lt;
$ This -gt; foo ();
statisch. foo ();
gt;
gt;

klasse B breidt A lt;
/ * Foo () worden gekopieerd naar B, vandaar de reikwijdte zal nog steeds A en
* De oproep succesvol te zijn * /
gt;

klasse C breidt A lt;
private function foo () lt;
/ * Originele methode wordt vervangen; de omvang van de nieuwe C * /
gt;
gt;

Het bovenstaande voorbeeld zal output:

resolutie late static binding ‘stopt bij een volledig opgelost statische oproep zonder fallback. Aan de andere kant, statische gesprekken met behulp van trefwoorden als ouder :: of zelf :: zal de bellende informatie doorsturen.

Voorbeeld # 4 Forwarding en non-forwarding gesprekken

lt;? php
klasse A, eerste klasse lt;
public static function foo () lt;
statisch. wie ();
gt;

public static functie die () lt;
echo __CLASS__. "\ n" ;
gt;
gt;

klasse B breidt A lt;
public static functietest () lt;
A. foo ();
ouder. foo ();
zelf. foo ();
gt;

public static functie die () lt;
echo __CLASS__. "\ n" ;
gt;
gt;
klasse C breidt B lt;
public static functie die () lt;
echo __CLASS__. "\ n" ;
gt;
gt;

Het bovenstaande voorbeeld zal output:

Ik heb enum uitgevoerd met behulp van late static binding.

lt;? php
-interface IEnum lt;
/ **
* Alleen concrete klasse moet deze functie die moet gedragen als implementeren
* Een enum.
*
* Deze methode moet de __CLASS__ constante eigenschap van die klasse terug te keren
*
* @return Snaar __CLASS__
* /
public static functie die ();
gt;

abstracte klasse Enum lt;

/ **
* De geselecteerde waarde voor de enum implementatie
*
* @var Gemengd
* /
public $ value;

publieke functie __construct ($ value) lt;
$ This -gt; value = $ value;
gt;

/ **
* De fabriek methode die het desbetreffende enum klasse creëert.
*
* @ Param integer $ soort
* @return Valse | \ klasse
* /
public static functie Factory (type $) lt;
if (leeg ($ type)) lt;
return false;
gt;

// Gebruik van late static binding aan de klas te krijgen.
$ Class = statisch. wie ();

if (array_key_exists ($ type. statisch. $ _enums)) lt;
return new $ klasse ($ type);
gt;

publieke functie getValue () lt;
terug $ deze -gt; waarde ;
gt;

public static functie GetValues ​​() lt;
terug array_keys (statische $ _enums.);
gt;

publieke functie getString () lt;
terug statisch. $ _enums [$ Deze -gt; waarde ];
gt;

publieke functie __toString () lt;
terug statisch. $ _enums [$ Deze -gt; waarde ];
gt;

class Fruits breidt Enum implementeert IEnum lt;

public static $ _enums = array (
1 = gt; ‘Appel’
2 = gt; ‘Oranje’
3 = gt; ‘Banaan’
)

public static functie die () lt;
terug __CLASS__;
gt;
gt;

// User input van dropdown menu van fruit lijst
$ Ingang = 3;

$ Fruit = Fruits. Factory ($ input);

$ Fruit -gt; getValue (); // 3
$ Fruit -gt; getString (); // Banana
?gt;

Sterker nog, er is een manier om de naam van de klas te krijgen waarin de trefwoorden ‘zelf’, ‘ouder’ of ‘statische’ verwijzen?
Voorbeeld:
lt;? php
class Base lt;
statische functie stuff () lt;
echo "Zelf: ". get_class (zelf);
echo "Ouder: ". get_class (ouder);
echo "afgeleid: ". get_class (statisch);
gt;
gt;
klasse afgeleid breidt Base lt;
statische functie stuff () lt;
statisch. stuff ();
gt;
gt;
?gt;

Ik denk niet dat er zou een massale bloat in de kern van PHP om dit alles te ondersteunen, maar het zou leuk zijn om te profiteren van het dynamische karakter van PHP.

En nog een kanttekening:
Als je in het geval-level scope bij een werkwijze van een base, en u wilt een top-level statische krijgen, hier is een lelijke oplossing (van Thacmus /lib/core.php – zie SVN repo):
lt;? php
// Get referentie [?] Om statische uit de klas
// $ Class – klasse naam of object (gebruikt get_class ())
// $ Var – Niet gaan zeggen
functie& get_static ($ class. $ var) lt; // ‘Static_get’?
if (! is_string ($ klasse)) $ class = get_class ($ klasse);
if (! @ property_exists ($ class. $ var)) lt;
trigger_error ( "Statische eigenschap bestaat niet: $ klasse. \ $ $ Var " );
// Debug_callstack (); // Dit is slechts een wrapper voor debug_backtrace () voor HTML
terug null;
gt;
// WINKEL referentie zodat de basisgegevens kunnen worden genoemd
// De code [[return eval ( ‘return &’. $ Klasse.’ :: $ ‘$ Var..’; ‘)]] Werkt niet – kan niet referenties terugkeren.
// Om de referentie vast te stellen, gebruikt u [[$ ref =&get_static (.)]]
eval ( ‘$ temp =&’. $ Klasse. ‘:: $’. $ Var. ‘;’ ); // gebruik
terug $ temp;
gt;
?gt;

@ Php op mikebird

U kunt argumenten om uw aannemer passeren uw getInstance methode, ervan uitgaande dat u werkt met php5.

public static functie getInstance ($ params = null) lt;
if (zelf :: $ objInstance == null) lt;
$ StrClass = statische :: getClass ();
zelf :: $ objInstance = new $ strClass ($ params);
gt;
terugkeren zelf :: $ objInstance;
gt;

Dit zou de params doorgeven aan uw aannemer. Liefde voor php.

zal dit werk voor variabelen ook?

het zou geweldig zijn, als de volgende werkte:

lt;? php
klasse A, eerste klasse lt;
beschermde statische $ table = "tafel" ;
public static functie connect () lt;
// Doen wat spullen hier
echo statisch. $ Tafel;
terug statisch. getInstance (); // GetInstance functie () kan nu terugkeren klasse A of B, afhankelijk van de context werd genoemd
gt;
.
gt;

klasse B breidt A lt;
beschermde statische $ table = "subtabel" ;
.
gt;

$ Table = B. connect (); // Hopelijk de output zal zijn: subtabel
?gt;

Proberen om een ​​erfelijke statische deel van een object door middel van een Singleton recreëren.

lt;? php
/ **
* "erfelijke statische" voor PHP lt; 5.3
* lt; lt; Library / Inheritable.php gt; gt;
* /

abstracte klasse Inheritable_Static breidt Singleton
lt;
gt;

abstracte klasse Overneembare
lt;
public static functie getStatic ($ className)
lt;
// Gebruik een abstract Singleton
terug Singleton. getInstance ($ className ‘_Static’.);
gt;

publieke functie goStatic ()
lt;
terug zelf. getStatic (get_class ($ this));
gt;
gt;

/ **
* Samenvatting
* lt; lt; Bibliotheek / LeesVoor / Abstract.php gt; gt;
* /

abstracte klasse SayIt_Abstract_Static breidt Inheritable_Static
lt;
public $ formaat;
gt;

abstracte klasse SayIt_Abstract breidt Overneembare
lt;
protected $ _name;

publieke functie __construct ($ name)
lt;
$ This -gt; _name = $ naam;
gt;

laatste publieke functie Sayit ()
lt;
echo sprintf ($ this -gt; goStatic () -gt;. format $ deze -gt; _name). "\ n" ;
gt;

/ **
* Betonnen
* lt; lt; Bibliotheek / LeesVoor / hallo.php gt; gt;
* /

class SayIt_Hello_Static breidt SayIt_Abstract_Static
lt;
gt;

class SayIt_Hello breidt SayIt_Abstract
lt;
public static functie getStatic () lt; terug ouder. getStatic (__CLASS__); gt;
gt;

SayIt_Hello. getStatic () -gt; format = «Hallo% s ‘;

$ W = new SayIt_Hello ( ‘World’);
$ J = new SayIt_Hello ( ‘Joe’);

echo $ w -gt; zeg het () ; // Hallo Wereld
echo $ j -gt; zeg het () ; // Hallo Joe

Hier is een kleine workaround heb ik gemaakt voor de statische erfenis kwestie. Het is niet perfect, maar het werkt.

// BaseClass klasse zal worden uitgebreid met een klasse nodig statische overerving workaroud
class BaseClass lt;
// Tijdelijk slaat klasse naam voor Entry :: getStatic () en Entry :: setNextStatic ()
beschermde statische $ nextStatic = false;

// Geeft de echte naam van de klasse aanroepen van de methode, niet degene waarin hij werd uitgeroepen.
beschermde statische functie getStatic () lt;
// Indien reeds opgeslagen
if (zelf. $ nextStatic) lt;
// Schoon en terugkeer
$ Class = zelf. $ NextStatic;
zelf. $ NextStatic = false;
terug $ klasse;
gt;

// In het
$ Backtrace = debug_backtrace ();
$ Class = false;

// Loop door
voor ($ i = 0; $ i lt; rekenen ($ Backtrace); $ I ++) lt;
// Als een klasse is gedefinieerd
if (isset ($ backtrace [$ i] [ ‘klasse’])) lt;
// Controleer of het niet een basis klasse
if (! in_array ($ backtrace [$ i] [ ‘klasse’], array ( ‘BaseClass’. ‘GenericClass’))) lt;
return $ Backtrace [$ i] [ ‘klasse’];
gt; anders lt;
$ Class = $ Backtrace [$ i] [ ‘klasse’];
gt;
gt; anders lt;
// Geeft laatst bekende klasse
terug $ klasse;
gt;
gt;

// Standaard
terug $ klasse;
gt;

// Als een statische methode binnen de wereldwijde env wordt genoemd, zal de vorige methode niet werkt, dus we moeten BaseClass vertellen welke
public static functie setNextStatic ($ class) lt;
// Value Save
zelf. $ NextStatic = $ klasse;
gt;
gt;

// Generic class verklaren verschillende statische methoden
class GenericClass breidt BaseClass lt;
public static $ name = ‘Generic’;

publieke functie getName () lt;
$ Static = get_class_vars (get_class ($ this));
terug $ static [ ‘naam’];
gt;

public static functie basicClassName () lt;
terug zelf. naam $;
gt;

public static functie staticClassName () lt;
// Get echte naam
$ StaticName = zelf. getStatic ();

// Terug final class naam
$ Static = get_class_vars ($ staticName);
terug $ static [ ‘naam’];
gt;
gt;

// Final klasse
class SomeClass breidt GenericClass lt;
public static $ name = ‘Sommige’;

public static functie returnClassNameWith ($ string) lt;
terug $ string. ‘. ‘. zelf. staticClassName ();
gt;
gt;

// Wordt afgedrukt ‘Sommige’
$ A = new SomeClass ();
echo ‘Naam van $ a. ‘. $ A -gt; getName (). ‘Lt; br / gt;’ ;

// Wordt afgedrukt ‘Generic’
Basic call echo ‘to SomeClass :: $ name. ‘. SomeClass. basicClassName (). ‘Lt; br / gt;’ ;

// Wordt afgedrukt ‘Generic’
Global call echo ‘to SomeClass :: $ name. ‘. SomeClass. staticClassName (). ‘Lt; br / gt;’ ;

// Wordt afgedrukt ‘Sommige’
BaseClass. setNextStatic (SomeClass ‘);
Global call echo ‘to SomeClass :: $ name met pre-set. ‘. SomeClass. staticClassName (). ‘Lt; br / gt;’ ;

// Wordt afgedrukt ‘Sommige’
echo ‘Interne oproep tot SomeClass :: $ name. ‘. SomeClass. returnClassNameWith (Dit is). ‘Lt; br / gt;’ ;

Er zijn twee problemen met deze tijdelijke oplossing:
– als je een statische methode van globale env bellen, moet u de naam van de klasse te verklaren voor het aanroepen van de methode, anders zal de tijdelijke oplossing niet werkt (zie 3 en 4 voorbeelden). Maar ik neem aan dat een goede programmering maakt paar telefoontjes om statische methoden van globale reikwijdte, dus dit moet niet lang vast te stellen als je het te gebruiken.
– de oplossing niet in slaagt om de toegang tot private of beschermde statische vars, omdat het gebruik maakt get_class_vars (). Als u een betere oplossing te vinden, laat het ons weten.

Met PHP 5.3.0, zal upgrading gemakkelijk zijn. alleen de methoden uit de basis-klasse te verwijderen, en zoek / elke oproep tot getStatic () en setNextStatic () te vervangen door statische. – Of men kon een selector op PHP_VERSION waarde gebruiken om ofwel de BaseClass bestand met tijdelijke oplossing of een BaseClass bestand met statische bevatten.

Dit werkte geweldig voor mij:

lt;? php
abstracte klasse ParentClass
lt;
statische functie parent_method ()
lt;
$ Child_class_str = zelf. get_child_class ();
eval ( "\ $ R = ". $ Child_class_str. ":: Abstract_static ();" );
terug $ r;
gt; // Kind moet negeren U ZICH IN HET SPOOR

beschermde abstract statische functie abstract_static ();

private static functie get_child_class ()
lt;
$ Backtrace = debug_backtrace ();
$ Num = count ($ backtrace);
voor ($ i = 0; $ i lt; $ Num; $ I ++)
lt;
if ($ backtrace [$ i] [ "klasse" ]! == __CLASS__)
return $ backtrace [$ i] [ "klasse" ];
gt;
terug null;
gt;
gt;

class ChildClass breidt ParentClass
lt;
statische functie parent_method () lt; terug ouder. parent_method (); gt;

beschermde statische functie abstract_static ()
lt;
terug __METHOD__. "()" ;
gt; // Van ParentClass
gt;

afdrukken "De oproep was: ". ChildClass. parent_method ();
?gt;

public static functie getInstance ()
lt;
terugkeren nieuwe zelf ();
gt;

$ Obj = B. getInstance ();

public static functie getInstance ()
lt;
return new statische ();
gt;

$ Obj = B. getInstance ();
?gt;

werkt ook op dezelfde manier met statische variabelen en constanten

Eenvoudige basis klasse die wordt gebruikt om get_called_class () om singleton instances te creëren. Een vorige post door php op mikebird dot co dot uk uitleggen hoe dit te doen, maar de uitgebreide statische variabelen vereisen dat u te definiëren in de kinderopvang klassen voordat ze werken.

abstracte klasse Singleton lt;
private static $ instances = array ();

publieke functie __construct () lt;
$ Class = get_called_class ();
if (array_key_exists ($ klasse. zelf. $ instances))
trigger_error ( "Geprobeerd om een ​​tweede exemplaar van de klasse \ construeren" $ Klasse \"". E_USER_WARNING);
gt;

public static functie getInstance () lt;
$ Class = get_called_class ();
if (array_key_exists ($ klasse. zelf. $ instances) === false)
zelf. $ Instances [$ klasse] = new $ klasse ();
terug zelf. $ Instances [$ klasse];
gt;
gt;

klasse A breidt Singleton lt;
gt;

klasse B breidt Singleton lt;
gt;

$ A1 = A. getInstance ();
$ A2 = A. getInstance ();
$ B1 = B. getInstance ();
$ B2 = B. getInstance ();

if (get_class ($ A1) == "EEN" &&
get_class ($ a2) == "EEN" &&
get_class ($ b1) == "B" &&
get_class ($ b2) == "B" &&
$ A1 === $ a2 &&
$ B1 === $ b2)
echo "Alle goede \ n" ;
anders
echo "FAIL! \ N" ;

Je hebt waarschijnlijk gemerkt dat het gebruik van het zelf. in plaats van statisch. dit is omdat we willen dat de statische variabele privé, en met behulp van statisch. zal ons niet toe om dat te doen.

Ik ben gestorven om dit probleem opgelost te zien. Ik ben zeer benieuwd naar de productie release van PHP 5.3.

In mijn geval heb ik geprobeerd om het volgende te doen:

klasse A, eerste klasse lt;
functie __construct () lt;
echo "Ik werd gebeld door ". statische :: __ CLASS__;
gt;
gt;

klasse B breidt A lt;
function foo () lt;
echo "Ik ben klasse ". __KLASSE__;
gt;
gt;

$ B = new B; // Moeten echo "Ik werd gebeld door B"
$ B-gt; Foo (); // Moeten echo "Ik ben klasse B"

Op dit moment heb ik de volgende oplossing:

klasse A, eerste klasse lt;
functie __construct ($ kind) lt;
echo "Ik werd gebeld door ". $ Kind;
gt;
gt;

klasse B breidt A lt;
functie __construct () lt;
ouder :: __ construct (__ CLASS__);
gt;

function foo () lt;
echo "Ik ben klasse ". __KLASSE__;
gt;
gt;

$ B = new B; // Echos "Ik werd gebeld door B"
$ B-gt; Foo (); // Echo "Ik ben klasse B"

Zoals u kunt zien, mijn huidige oplossing heeft een aantal overhead en is niet zo waterdicht als de late static binding methode.

publieke functie __construct ($ enumKeyOrVal)
lt;

unset ($ this -gt;. toString $ this -gt; toInt);

$ Enums = $ deze -gt; enums ();

als(
leeg ($ enumKeyOrVal)
||
!(Isset ($ enums [$ deze -gt; num = $ enumKeyOrVal])
||
($ Deze -gt; num = array_search ($ enumKeyOrVal $ enums).) == False)!
)
$ This -gt; num = 0;

/ **
* 5.3 Version
* /
/ *
* als(
leeg ($ enumKeyOrVal)
||
!(Isset (statische :: $ enums [$ this-gt; num = $ enumKeyOrVal])
||
($ This-gt; num = array_search ($ enumKeyOrVal, statische :: $ opsommingen)) == false)!
)
$ This-gt; num = 0;
* /
gt;

publieke functie enums ()
lt;
$ Vars = $ deze -gt; vars ();
terug $ vars [ ‘opsommingen’];
gt;

publieke functie __get ($ eigendom)
lt;
if (method_exists ($ this. ‘__’. $ eigenschap))
terug $ deze -gt; lt; ‘__’. $ woning gt; ();
anders
terug $ deze -gt; __toString ();
gt;

publieke functie __toInt ()
lt;
terug $ deze -gt; num;
gt;

publieke functie __toString ()
lt;

$ Enums = $ deze -gt; enums ();

if (isset ($ enums [$ deze -gt; num]))
lt;
terug $ enums [$ deze -gt; num];
gt;
anders
lt;
terug $ enums [0];
gt;

class Posities breidt EnumBase
lt;
public static $ enums = array (
0 = gt; ‘Bilinmiyor’
1 = gt; ‘Kale’,
2 = gt; ‘Defans’,
3 = gt; ‘Orta Saha’,
4 = gt; ‘Forvet’
);
gt;

$ A = nieuwe posities ( ‘Orta Saha’);
$ B = nieuwe posities (4);

$ C = (string) $ a; // Orta Saha
$ D = (string) $ b; // Forvet
?gt;

Bron: php.net


Read more

  • NYIAD Artikelen van het Ontwerp – Larisa Belenitsky Tips

    Tips voor Decorating Children kamers – Larisa Belenitsky op Room Design for Kids In de afgelopen jaren, zoals de economie is gegroeid, een sector van het interieur ontwerp-industrie heeft…

  • Problemen oplossen Maak een Tabel

    Problem Solving: Maak een Tabel Wat is het? Maak een tabel is een probleemoplossende strategie die leerlingen kunnen gebruiken om wiskundige woord problemen op te lossen door het schrijven van…

  • Gedichten, Poëzie – Quotes

    Referenties: POEMS POËZIE Poëzie is een communicatiemiddel, gedichten over het leven kunnen beschrijven hoe we ons voelen of te uiten onze hoop en dromen voor de toekomst. gedichten kan worden…

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *

fifteen − four =