Vyřešení circular reference a registrace eventu
- akadlec
- Člen | 1326
Na radu Filipa (tímto mu velice děkuji za jeho čas) jsem si v DI extension upravil přidání události kterou chci aby se spustila a nevyvolala circular reference error.
$builder->getDefinition('application')
->addSetup('$self = $this; $service->onRequest[] = function () use ($self) { $self->getService(?); }', array($this->prefix('onRequestHandler')))
Služba onRequest handler pak obsahuje magickou metodu __invoke která provede požadované operace. Problém je ale v tom že se to při téhle definici nespustí. Aby se provedl invoke musím to upravit takhle:
$builder->getDefinition('application')
->addSetup('$self = $this; $service->onRequest[] = function () use ($self) { call_user_func($self->getService(?)); }', array($this->prefix('onRequestHandler')))
a když to samo volám takto tak se nepředají ty parametry co by se normálně předaly (Nette\Application\Application atd.) ale to mě až tak nevadí.
Co dělám špatně? Je to postaveno na nette 2.1.dev
- Filip Procházka
- Moderator | 4668
Ty přece tu metodu __invoke()
na té službě vůbec nevoláš.
Máš problém na úrovni PHP, né Nette.
Když přidáváš event ručně, v Compiler Extension
$builder->getDefinition('application')
->addSetup('$self = $this; $service->onRequest[] = ...', array($this->prefix('onRequestHandler')))
tak by tohle fungovalo, ale vzniká ti možnost circural reference. Všimni si že předáváš do eventu instaci objektu, který je sám callable. Když se tedy zavolá event, tak event spouští tento tvůj callback.
$self->getService(?);
Ty jsi ale udělal jen to, že jsi službu vytáhl, ale už jsi nijak
neinvokoval, tedy se __invoke()
nemohlo zavolat, protože invoke v
ObjectMixin
se aplikoval na closuru, nikoliv na tvoji službu
function () use ($self) { $self->getService(?); }
Naproti tomu, když tam přidáš ještě to call_user_func
, tak
už se tvoje služba nejen vytvoří, ale i se invokne, protože když do
call_user_func
předáš objekt, tak ti nad ním zkouší
zavolat __invoke
function () use ($self) { call_user_func($self->getService(?)); }
Jenže tomu pořád něco chybí, nepředávají se argumenty :) Takhle už je to kompletní:
function () use ($self) { call_user_func_array($self->getService(?), func_get_args()); }
No a nebo, pokud si chceš tohle všechno ušetřit můžeš prostě použít kdyby/events :)
- akadlec
- Člen | 1326
Mno to sem tak nějak pochopil, proto jsem si tam hodil to call_user_func aby se ten call provedl ;) no ale právě jak si mě v issue nasměroval tímto směrem tak sem čekal nějakou magii na straně nette ;)
Jinak kdyby/events zvažuji že tam asi hodím pro ušetření zbytečných problémů ;)
- Filip Procházka
- Moderator | 4668
No call_user_func
, jak jsme si ukázali ale nestačí. S tím
func_get_args
to už ale funguje, ne? :)
V Nette na to žádná magie není, nejspíš proto že to nikdo moc často nepotřebuje.