Experiment NetteExtras\ExtensionObjects
- Panda
- Člen | 569
Zdravím všechny,
včera jsme se s Majklem trochu bavili o přicházejícím PHP 5.4 a řeč
došla i na chystané traity. Zmiňoval jsem, že jdou částečně emulovat již
dnes, nicméně trochu krkolomně. Po troše toho krčního lámání jsem měl
v ruce funkční základ a došlo mi, že můj výtvor se trochu podobá
extension metodám, jen je to v některých ohledech trochu
šikovnější…
O co tedy jde? Podívejte se na následující dvě třídy:
/**
* @use(Hello)
*/
class Greeter extends ExtensibleObject
{
protected $name = 'World';
protected function getMark()
{
return '!';
}
}
class Hello extends ExtensionObject
{
public function hello()
{
return 'Hello, ' . $this->name . $this->getMark();
}
}
Co myslíte, že udělá následující kód?
$greeter = new Greeter();
echo $greeter->hello();
Tušíte správně, vypíše
Hello, World!
Anotace @use(Hello)
říká třídě Greeter
, že
má použít třídu Hello
jako rozšiřující objekt. Z metod
rozšiřujícího objektu je možno přistupovat k public
a
protected
členům stejně, jako kdybychom byli přímo v dané
třídě. Z třídy samotné (ani z jejich rozšiřujících tříd) však
nelze přistupovat k protected
členům jednotlivých
rozšiřujících tříd, protože by pak muselo dojít k jejich
zpřístupnění i pro okolní objekty.
Jedinými podmínkami je, aby základní třída byla potomkem
NetteExtras\ExtensionObjects\ExtensibleObject
(potomek
Nette\Object
, takže nepřijdete o jeho funkčnost) a třídy
rozšiřující potomky
NetteExtras\ExtensionObjects\ExtensionObject
. Z technických
důvodů (celé je to realizováno přes magické metody) nelze překrývat
metody, které již ve třídě existují.
Rozšiřujících tříd může být i víc:
/**
* @use(Hello, Bonjour, French)
*/
class Greeter extends ExtensibleObject
{
protected $name = 'World';
protected function getMark()
{
return '!';
}
}
class Hello extends ExtensionObject
{
public function hello()
{
return 'Hello, ' . $this->name . $this->getMark();
}
}
class Bonjour extends ExtensionObject
{
public function bonjour()
{
return 'Bonjour, ' . $this->name . $this->getFrenchMark();
}
}
class French extends ExtensionObject
{
public function getFrenchMark()
{
return ' !';
}
}
$greeter = new Greeter();
echo $greeter->hello(), PHP_EOL, $greeter->bonjour();
Hello, World!
Bonjour, World !
Pokud dvě extension třídy obsahují stejný člen, použije se ta, která
byla uvedena jako první. V našem případě budou mít tedy členy z
Hello
přednost před členy z Bonjour
.
Další hezké věci, které to zatím umí:
- Properties v rozšiřujících objektech
- Eventy v rozšiřujících objektech
- Dynamické přidávání extension objectů:
Greeter::extensionObject('Dynamic');
Kód naleznete na GitHubu: ExtensionObjects. Pro další ukázky použití se doporučuji podívat na testy.
Co myslíte, má to nějaké praktické využití? Líbí se vám to? Má smysl to nějakým způsobem dál optimalizovat (nyní se hojně využívá reflexe, což má negativní dopad na výkon)?
- westrem
- Člen | 398
Mozno sa mylim, ale nie je toto v podstate implementacia viacnasobneho dedenia aj pre objekty?
Ako pride mi to pekne, urcite niekde aj vyuzitelne, lenze umoznuje to robit velke prasarny a neviem si predstavit takuto „silnu hracku“ v rukach neskusenych PHP programatorov, ktori maju len male povedomie o Navrhovych vzoroch a OOP obecne.
- westrem
- Člen | 398
vrtak-cz napsal(a):
Nemýlíš se traits je vpodstatě implementace Mixinů v PHP. Jelikož je to novinka které zatím není ve stable verzi a většina bastličů „zaspala“ dobu (používá hodně často PHP 4 nebo 5). Takže bych se toho nebál…
No ja som Mixins doteraz poznal len vramci CSSka, nejak mi uniklo, ze je to obecnejsi programatorsky princip. Kazdopadne „traits“ – „https://en.wikipedia.org/wiki/Trait_(computer_science)“ sa od Mixinov trochu lisia.
K zaspaniu doby: Nedefinoval by som to uplne tak, ze ak pouzivam napr PHP 5.2 tak som zaspal dobu. Niekedy hosting neposkytuje 5.3 alebo len v nejakom experimentalnom nastaveni. Castokrat (to je ale mojou povahou) sa pustam do novych veci az ked su widely spreaded, stable a pouzivane. Dovtedy o nich v podstate len „vegetativne viem“, poznam ich, ale nepouzivam. Rovnako je to aj s PHP 5.3. Chapem vyhody NS, tak isto late static bindingu, ale zatial som nikdy az tak nepotreboval a vedel sa zaobist aj bez nich, preto nemam dovod ist na 5.3 a ostavam na overenej 5.2. Jedine co mi z 5.3 obcas chyba su anonymne funkcie.