Experiment NetteExtras\ExtensionObjects

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Panda
Člen | 569
+
0
-

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
+
0
-

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.

Patrik Votoček
Člen | 2221
+
0
-

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…

westrem
Člen | 398
+
0
-

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.