Komponenta v komponentě, DI, jak řešit
- joe
- Člen | 313
Ahoj, prosím, máte někdo nějaký funkční kód, jak řešit komponenty v komponentách a předávání závislostí? Prošel jsem fórum, zkouším, co mě napadá, ale nějak nemůžu najít řešení.
Jednoduše mám komponentu (C1), ke které mám napsaný interface (s metodou create), pak se nějakým způsobem vygeneruje továrnička. Komponenta C1 ale vyžaduje další komponentu. Jak ji předám, co mám kde nastavit, jak napsat? Díky za uvedení do děje. Nemůžu přijít na to, jakým způsobem to řešit dále do hloubky, našel jsem řešení jen do první úrovně (komponenta C1 bez dalších závislostí).
- Etch
- Člen | 403
No je to stejné jako každá jiná závislost. Prostě si jí vyžádej v konstruktoru.
interface C1Factory{
/** @return \C1 */
public function create();
}
interface C2Factory{
/** @return \C2 */
public function create();
}
class C2 extends Control{
public function render(){
//...
}
}
class C1 extends Control{
private $c2Factory;
public function __construct(C2Factory $c2Factory){
parent::__construct();
list($this->c2Factory) = func_get_args();
}
public function render(){
//...
}
protected function createComponentC2(){
return $this->c2Factory->create();
}
}
- joe
- Člen | 313
Díky za odpověď, vyzkouším na PC, minimálně ale nerozumím tomu, že konstruktor C1 má teď jen jeden parametr. Předání přes konstruktor byla první z věcí, co mě napadla, ale pokud novou závislost dám na první pozici v seznamu parametrů, kam se ztratí původní parametry od Control? Pokud dávám další závislost na poslední místo, pak řadím povinnou závislost za nepovinné. V ani jednom případě mi to nepřijde moc srozumitelné…
- jiri.pudil
- Nette Blogger | 1032
Parametry v konstruktoru Nette\Application\UI\Control (edit:
Nette\ComponentModel\Component
) tam jsou jenom kvůli zpětné
kompatibilitě, nemusíš je vůbec předávat, a tedy ani vyžadovat
v konstruktoru potomka.
Editoval jiri.pudil (25. 12. 2014 14:44)
- joe
- Člen | 313
Tak díky za rady, už to funguje, ale prvnotní hraní byl teda boj… Je škoda, že to není tak dobře zdokumentované (je to taky dost těžké, když se to tak často mění), jako to tady znají lidé na fóru, pak se s tím člověk, který se nezajímá přímo o vývoj, docela pere… V diskusích je plno rad, ale na starší verzi, takže se naráží na překážky.
- David Kudera
- Člen | 455
@Etch
jen taková poznámka mimo k tomuto kódu:
list($this->c2Factory) = func_get_args();
jako machrovinka schopnosti napsat to na jeden řádek asi dobrý, ale úplně si nejsem jistý, jestli je tak dobrý to ukazovat na fóru. Spíš bych to rozepsal normálně.. Navíc když je v konstruktoru jen jeden argument… Když pak přijde začátečník, tak aby si hned neřekl „tohle je tady best practise“ a přitom ani nebude vědět, co vlastně napsal. Možná ale říkám blbost a určitě je to i věc názoru :-)
- Etch
- Člen | 403
@DavidKudera :
- nevím, co je za machrovinku na použití dvou relativně základních fukcí PHP a ani nevím, proč by měl být tento „alternativní zápis“ na fóru nějaké tabu.
- samozřejmě to můžeš rozepsat normálně, když jseš na to zvyklej :)
- nikdy jsem nikde neřekl, že je to „best practice“. Tohle je prostě
v daném případě naprosto ekvivalentní zápis s
$this->c2Factory = $c2Factory;
využívající celkem základních PHP funkcí.
to mi přijde, jako kdybych nesměl napsat:
while(list($key, $val) = each($array)){
//...
}
místo
foreach($array as $key => $val){
//...
}
nebo
while(/** ... */):
//...
endwhile;
místo:
while(/** ... */){
//...
}
aby to náhodou někdo nepovažoval za „best practice“.
Zastávám názor, že pokud začátečník obecně něco bezhlavě okopíruje, začne to používat, aniž by věděl co to vlastně dělá a ani si to nenajde v manuálu, tak směřuje do pekel. :D
Editoval Etch (26. 12. 2014 0:13)
- Mysteria
- Člen | 797
@Etch: Dobrovolně se přiznám, že ačkoliv v PHP píšu už přes 4 roky, tak na tenhle zápis
while(list($key, $val) = each($array)) { ... }
bych se asi taky radši mrknul do PHP manuálu. :) Jako pochopit se to dá asi i bez něj, ale že bych tohle někde viděl si teda nepamatuju.
Každopádně co se týká tohohle, tak na tom mi zase naopak nic divnýho nepřipadá i když to nepoužívám, protože IDE generuje konstruktory klasickým stylem.
list($this->param1, $this->param2) = func_get_args();
- Šaman
- Člen | 2666
Na tomhle zápisu se mi nelíbí, že když změním pořadí parametrů (třeba kvůli tomu, aby automaticky vložitelné závislosti byly na konci), tak rozbiju kód. Při klasickém zápisu to je v pohodě. Jediná výhoda je, že předáš všechny parametry na jednom řádku.
A přitom foreachi mi připadá nesmysl psát delší a nepřehlednější zápis místo jednoduššího a čitelnějšího.
endwhile nepoužívám, ale je čitelný a nemá WTF faktor, tak proč ne.
- Etch
- Člen | 403
@Mysteria:
Ten zápis jsem uvedl právě z důvodu, že mi nepřijde ideální tahat pojem „best practice“ do čistě zvykových věcí. Pokud má člověk před sebou dva zcela ekvivalentní zápisy, tak hovořit o jednom z nich, že asi není dobré ho ukazovat mi nepřijde jako ideální stav. :) Tahání „best practice“ i do takhle základních záležitostí mi přijde spíše na škodu, protože „začátečník“ nabušený znalostí takovéhle pseudo „best practice“ najednou bude potřebovat přetěžovat konstruktor a bude na to koukat jak husa do flašky. :D
@Šaman:
Alternativní zápis foreache byl uveden pouze jako příklad. Nevýhody toho
zápisu, který používám jsou jasné a nikdo je také nepopírá. Krom toho
co si uvedl je například další nevýhoda, že by se neměl používat na
nepovinné parametry, protože když nebude parametr předán, tak to vyhnije na
nedefinovaný offset. Zrovna u list() = func_get_args()
mi přijde,
že žádný WTF faktor taky není. Není to žádná magie, ale použití
běžných funkcí.
Editoval Etch (26. 12. 2014 2:22)
- LeonardoCA
- Člen | 296
No, mne se ten zapis taky moc nelibi, i kdyz nekdy se urcite muze hodit, ale preferuju jednoznacne prirazeni.
Krom duvodu co uz padly, tak me jeste napadl jako duvod rychlost – prirazeni do promenne je vzdycky rychlejsi nez volani funkce a protoze me to zajimalo, zkusil jsem napsat jednoduchy benchmark.
private $var1;
private $var2;
private $var3;
public function testSimpleAssignment($var1, $var2, $var3)
{
$this->var1 = $var1;
$this->var2 = $var2;
$this->var3 = $var3;
}
public function testFuncGetArgs($var1, $var2, $var3)
{
list($this->var1, $this->var2, $this->var3) = func_get_args();
}
public function benchmark()
{
$numberOfCalls = 10000;
sdump($numberOfCalls);
Debugger::timer('assignment');
for ($i=0; $i<$numberOfCalls; $i++) {
$this->testSimpleAssignment(1,2,3);
}
sdump(Debugger::timer('assignment'));
Debugger::timer('func_get_args');
for ($i=0; $i<$numberOfCalls; $i++) {
$this->testFuncGetArgs(1,2,3);
}
sdump(Debugger::timer('func_get_args'));
}
public function render()
{
$this->benchmark();
}
Zaver pro mne: prime prirazeni do promenne je sice priblizne 2× rychlejsi, ale na rychlem stroji je to v beznych pripadech zanedbatelne. (testoval jsem na PHP 5.5.9, 64bit linux)
Editoval LeonardoCA (26. 12. 2014 15:38)
- Filip Procházka
- Moderator | 4668
Přiřazení argumentů konstruktoru do properties třídy jde krásně generovat, například v PhpStormu.