Dependency Injection ve 2.1: Anotace @inject

Upozornění: Tohle vlákno je hodně staré.

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

Majkl578 napsal(a):

Nikoliv, dostuduj si prosím realitu. Inject metody se volají na všech službách, ne pouze presenteru.

A tvrdím snad někde něco jiného? Realitu mám dostudovanou na výbornou. Vím moc dobře, jak celý DIC v Nette funguje, ale děkuji za zájem ;) To že se volají i na službách je nepodstatné, ovšem ničemu to nevadí, ba dokonce se to hodí, teď když PresenterFactory, hledá presentery i v DI Containeru.

Podstatné je, jaký má být doporučovaný postup injektování závislostí do presenterů, protože u modelových tříd (tady čti pozorně) by se mělo (vidíš? napsal jsem mělo, né musí) upřednostňovat constructor injection a neexistuje žádný relevantní důvod dělat to jinak.

Pokud si neumíš návrh aplikace rozvrhnout tak, abys neměl v jedné modelové třídě 15 závislostí, tak je to jen a pouze tvoje chyba :)

Editoval Filip Procházka (28. 4. 2013 18:06)

před 7 lety

Majkl578
Moderator | 1376
+
0
-

Filip Procházka napsal(a):
To že se volají i na službách je nepodstatné, ovšem ničemu to nevadí, ba dokonce se to hodí, teď když PresenterFactory, hledá presentery i v DI Containeru.

Což tedy presenter dělá službou. To jen potvrzuje, že diskuze je obecná, nikoliv pouze o presenterech.

Podstatné je, jaký má být doporučovaný postup injektování závislostí do presenterů, protože u modelových tříd (tady čti pozorně) by se mělo (vidíš? napsal jsem mělo, né musí) upřednostňovat constructor injection a neexistuje žádný relevantní důvod dělat to jinak.

Možná bys prvně mohl zkusit ubrat na aroganci.
A kdy se tahle diskuze přehoupla od obecnosti k presenterům? Tahle diskuze je od počátku o "Dependency Injection ve 2.1: Anotace @inject" (jak zní i v titulku) a v Davidově 1. příspěvku nestojí nic o presenterech. Jde tedy o diskuzi nad obecnou implementací v DIc, která funguje obecně a nerozlišuje presenter/službu.
Presenter i modelová třída jsou z obecného hlediska totéž. Stejně tak jako lze pravidlo o množství závislostí aplikovat na modelové třídy, lze jej aplikovat i na presentery.
Nicméně relevantní důvod zjevně existuje (příkladem jsou právě presentery), když je to potřeba implementovat na úrovni DIc. ;)

Pokud si neumíš návrh aplikace rozvrhnout tak, abys neměl v jedné modelové třídě 15 závislostí, tak je to jen a pouze tvoje chyba :)

Nikde jsem nic takového neřekl, zkus si prosím nevymýšlet nesmysly, jen abys měl jak na ostatní útočit.

Editoval Majkl578 (29. 4. 2013 2:48)

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

Majkl578 napsal(a):

Možná bys prvně mohl zkusit ubrat na aroganci.

Od tebe to zní opravdu legračně :)

A kdy se tahle diskuze přehoupla od obecnosti k presenterům? Tahle diskuze je od počátku o "Dependency Injection ve 2.1: Anotace @inject" (jak zní i v titulku) a v Davidově 1. příspěvku nestojí nic o presenterech.

Však ano, to ovšem znamená, že je o presenterech ;) Použil bys snad někdy v modelu @inject? Nepoužil. I když konkrétně ty možná, kdyby bylo povoleno @inject do private přes reflexi, ale to naštěstí David neudělá. To že to dělá Java to neospravedlňuje. Není to totiž čistý způsob injekce a proto by neměl být přímo ve frameworku. (Napiš si extension, když potřebuješ za každou cenu porušovat zapouzdření třídy)

Nicméně relevantní důvod zjevně existuje (příkladem jsou právě presentery), když je to potřeba implementovat na úrovni DIc. ;)

Tedy mi dáváš za pravdu, že nemá smysl řešit obecné služby. Problémem jsou pouze presentery . Žádný jiný typ služby, kde by byly potřeba @inject jsi totiž zatím neuvedl. Nikdo tě na službách nenutí používat @inject nebo inject*().

Proč by to DI Container neměl umět? Už teď umí injekci do properties pomocí setup $db(@DibiConnection). Stejně tak inject*() je jenom lépe pojmenovaný setter, nic jiného. A to že je DIC volá automaticky je jenom forma autowire. Stejně jako nepíšeš, co se má předat do konstruktoru, protože to zanalyzuje přes typehinty, tak tady nemusíš vypisovat položky do setup, protože jsou zde naznačené. Jenom ti to šetří psaní, nic jiného. Je to nepovinné a perfektně přenositelné do jakéhokoliv jiného DI Containeru, který umí všechny 3 typy injekce.

Nikde jsem nic takového neřekl, zkus si prosím nevymýšlet nesmysly, jen abys měl jak na ostatní útočit.

Já jsem přece neřekl že to neumíš. Nauč se prosím pozorně číst, když už se potřebuješ za každou cenu hádat, jinak nemá smysl se s tebou vůbec bavit ;)

Editoval Filip Procházka (29. 4. 2013 7:26)

před 7 lety

Milo
Nette Core | 1153
+
0
-

@dg Plánuješ podporu inject… metod ve 2.2 úplně odebrat a ponechat jen @inject a konstruktor injection? Nebo inject… zachovat ale preferovat anotaci?

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

Asi by bylo záhodno povolit metody inject jen pro presentery.

Imho by bylo nejlepší nastavit inject na službách z defaultního true na false. Ovšem když teď mohou být presentery v DIC, tak si nejsem úplně jistý. Rozhodně bych to ale neodstraňoval, občas je to šikovné :)

Podmínkovat to typem třídy by asi bylo trochu magické (aby presentery měly inject:true v dic), dost by ten zápis zjednodušilo, kdyby se dalo psát

services:
	App\SignPresenter: # nesnáším vymýšlení názvů pro služby :)
		arguments: [@a, ..., @b] # konstruktor se stejně skoro vždy doplní sám
		inject: on
		setup: # u presenterů většinou stačilo nastavovat pár věcí v setup
			- $property(@Some\Service)
			- $productionMode(%productionMode%) # hlavně jsou definitivně vyřešeny parametry :)

vs

services:
	signPresenter:
		class: App\SignPresenter(@a, ..., @b)
		inject: on

Btw, měl jsem dojem, že tohle jeden čas fungovalo.. mám poslat pullrequest?

Editoval Filip Procházka (29. 4. 2013 10:29)

před 7 lety

pekelnik
Člen | 468
+
0
-

Ještě bych se vrátil k Majklovo návrhu injektáže do private properties. Byl zde pokud vím zmíňen jediný důvod proti:

Třída se nehlásí k závislostem a tudíž nemůže být řeč o injektáži závislostí.

Domnívám se, že pokud někdo oželí mít možnost injektovat takovou property jinak než reflexí – může být taková závislost jednoznačně deklarovaná použitím anotace @property nad třídou. Výborné by to bylo na prototypování. Pokud jde o testování není nic jednoduššího než si nechat takovou službu prostě vyrobit.

Zkrátka neshledávám objektivní důvody pro tak rychlé smetení návrhu ze stolu.

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

Ale na prototypování se dá výborně použít i @inject do public property. Nebo se pletu? Pokud je to prototyp, tak to přeci přepíšeš, až to bude funkční, stejně jako by jsi to udělal u @inject do private, že? ;)

Editoval Filip Procházka (29. 4. 2013 12:26)

před 7 lety

mishak
Člen | 100
+
0
-

Přesně tak argumentace prototypováním je zcestná to není smysl @inject.
Pokud chcete prototypovat udělejte si extension prototyping co všechno přegeneruje/obalí a nastaví.

Chtělo by to přesně říct čeho se týká původní návrh, protože zítra to tu bude čistě FLAME.

EDIT:

Výborné by to bylo na prototypování. Pokud jde o testování není nic jednoduššího než si nechat takovou službu prostě vyrobit.

Toto nelze pochopit jinak než jako argument pro zachování.

Editoval mishak (29. 4. 2013 21:21)

před 7 lety

pekelnik
Člen | 468
+
0
-

S tím prototypováním to není argumentace – pouze zmínka ;)

před 7 lety

Milo
Nette Core | 1153
+
0
-

pekelnik napsal(a):

Ještě bych se vrátil k Majklovo návrhu injektáže do private properties. Byl zde pokud vím zmíňen jediný důvod proti:

Třída se nehlásí k závislostem a tudíž nemůže být řeč o injektáži závislostí.

Zkrátka neshledávám objektivní důvody pro tak rychlé smetení návrhu ze stolu.

Hlavní proti je, že objekt takové třídy nevyrobíš bez DIC.

před 7 lety

castamir
Člen | 630
+
0
-

Pokud se mají inject* metody zrušit, očekával bych jejich plnohodnotnou náhradu, což anotace do public property IMHO není. Osobně se mi líbí návrh od @šamana, ale ta úprava Nette\Object by asi byla hodně drahá. @autowire od @hosiplana se naopak nedá použít mimo presentery, ale zase je lazy ;-).

Asi bych ty inject* metody ještě neodepisoval…

před 7 lety

mkoubik
Generous Backer | 731
+
0
-

Jen abych se v tom zorientoval – chápu to správně, že specifičnost presenterů spočívá v tom, že zcela programově zneužívají dědičnost ke sdílení funkcionality? Dřív byla potíž ještě v tom, že nešly konfigurovat pomocí DI kontejneru – to už je vyřešené. Jinak pokud máš správně navržené presentery, tak není důvod aby měly víc něž pár závislostí. Od ostatních služeb se tedy liší jen tím, že se kvůli dědičnosti špatně používá constructor injection?

před 7 lety

Majkl578
Moderator | 1376
+
0
-

Milo napsal(a):

Hlavní proti je, že objekt takové třídy nevyrobíš bez DIC.

Vyrobíš, reflexe je součástí PHP, ne DIc.
Tedy rozdíl mezi nastavení hodnoty private a public property je jen více kódu (který samozřejmě lze separovat do helper funkce):

class T { public $pubDep; private $privDep; }

$obj = new T();

// public
$obj->pubDep = new Foo();

// private
$rdep = new ReflectionProperty($obj, 'privDep');
$rdep->setAccessible(TRUE);
$rdep->setValue($obj, new Bar());

Výhoda private property je zřejmá – zapouzdřenost objektu není narušena požadavky DI (DIc).
Nevýhoda taktéž – závislost není na první pohled vidět zvenčí.

Editoval Majkl578 (30. 4. 2013 5:15)

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

Majkl578 napsal(a):

Výhoda private property je zřejmá – zapouzdřenost objektu není narušena požadavky DI (DIc).

To není práva, reflexí jsi zapouzdřenost porušil. Zapouzdřenost znamená, že s objektem pracuješ pouze jeho veřejným API. Reflexe rozhodně není veřejné api objektu.

mkoubik napsal(a):

Jen abych se v tom zorientoval – chápu to správně, že specifičnost presenterů spočívá v tom, že zcela programově zneužívají dědičnost ke sdílení funkcionality?

Ono to není tak jednoduché. Tohle sdílení funkcionality dává velký smysl, protože jednotlivé moduly mají představovat hlubší struktury web, tedy je jenom logické, že když jsi například v modulu katalog, tak jeho presentery využívají katalogové modely (konkrétní) a modely cmska (celku).

Myslím, že jsem to dobře vysvětlil tady :)

Dřív byla potíž ještě v tom, že nešly konfigurovat pomocí DI kontejneru – to už je vyřešené.

To byl velký problém, protože „já chci používat service locator“ nettisti přišli o nejlepší argument (jak předat parametry do presenteru) :)

Od ostatních služeb se tedy liší jen tím, že se kvůli dědičnosti špatně používá constructor injection?

Přesně tak :)

Editoval Filip Procházka (30. 4. 2013 9:12)

před 7 lety

duke
Člen | 650
+
0
-

Filip Procházka napsal:

Majkl578 napsal:

Výhoda private property je zřejmá – zapouzdřenost objektu není narušena požadavky DI (DIc).

To není práva, reflexí jsi zapouzdřenost porušil. Zapouzdřenost znamená, že s objektem pracuješ pouze jeho veřejným API. Reflexe rozhodně není veřejné api objektu.

Myslím, že @Majkl578 rozlišuje mezi zapouzdřením v rámci vytváření a zapouzdřením v rámci používání vytvořeného objektu. Ano, zápis do private property je porušením zapouzdření, ale předpokládá se, že toto porušení během vytváření objektu bude jediné takové porušení. Tj. při vytváření se jednou porušuje zapouzdření pomocí reflexe, aby se vyloučila možnost jeho porušení běžnými prostředky (tj. bez použití reflexe) v rámci jeho používání v aplikaci. Platí zde tedy, že účel světí prostředky. Dovolím si ocitovat Filipa Procházku z článku, kde – jak sám říká – to tak „dobře vysvětlil“:

Filip Procházka napsal:

Když už porušujeme pravidla, musíme vědět proč a jaká ;)

Toto platí zejména, pokud vnímáme property injection pouze jako jakýsi syntaktický cukr. Cituji:

David Grudl napsal:

Anotaci @inject vnímám čistě jako syntax sugar pro rutinní předání závislostí přes konstruktor.

… neboť je-li to jen syntaktický cukr pro rutinní předání závislostí, pak by měla anotace @inject disponovat stejnou silou jako konstruktor v tak rutinní záležitosti jako nastavení závislosti, která bude zapouzdřena (tj. private, či protected).

Zároveň platí, že je-li to pouze syntaktický cukr, pak tento rozšiřuje definici veřejného API, neboť je-li součástí veřejného API konstruktor, pak by měl být jeho součástí i tento syntaktický cukr.

Pokud máte argument, který takovému rozšíření definice veřejného API brání, rád bych ho slyšel. Odkud vlastně čerpáte svou definici veřejného API?

před 7 lety

mkoubik
Generous Backer | 731
+
0
-

mkoubik napsal(a):

Jen abych se v tom zorientoval – chápu to správně, že specifičnost presenterů spočívá v tom, že zcela programově zneužívají dědičnost ke sdílení funkcionality?

Ono to není tak jednoduché. Tohle sdílení funkcionality dává velký smysl, protože jednotlivé moduly mají představovat hlubší struktury web, tedy je jenom logické, že když jsi například v modulu katalog, tak jeho presentery využívají katalogové modely (konkrétní) a modely cmska (celku).

To jsem rozhodně nemyslel tak, že je to špatně, jen je potřeba počítat s tím, že presentery tuhle vlastnost mají. Tím „programově zneužívají“ jsem myslel „vědomě a opodstatněně zneužívají“.

před 7 lety

pekelnik
Člen | 468
+
0
-

@duke: +1

Editoval pekelnik (30. 4. 2013 13:23)

před 7 lety

pekelnik
Člen | 468
+
0
-

@Filip Procházka:

… reflexí jsi zapouzdřenost porušil. Zapouzdřenost znamená, že s objektem pracuješ pouze jeho veřejným API. Reflexe rozhodně není veřejné api objektu …

Dovolil bych si nesouhlasit. Veřejné API je jasně deklarované anotací @property nad danou třídou. Reflexe je v tomto případě pouze ne zcela běžný jazykový prostředek.

Editoval pekelnik (30. 4. 2013 13:30)

před 7 lety

David Grudl
Nette Core | 7148
+
0
-

Tak jo, příznivci private property injection, napište mi kód, který vytvoří instanci třídy Nette\Security\User AnyClass, předá ji všechny závislosti a zkontroluje jejich typ, zda je platný.

Vykopávám s konstruktor injection:

$user = new AnyClass($a, $b, $c);

před 7 lety

Tharos
Člen | 1042
+
0
-

@dg: Proč by do třídy tohoto typu chtěl vůbec někdo předávat závislosti jinak, než pomocí konstruktoru?

Myslím, že už zde probíhá diskuze jen o presenterech, které mají svá specifika.

Jestli chceš diskuzi zahrát do autu tím, že ji nasměruješ do vod, kde je použití private property injection nesmysl, je to Tvá volba…

Editoval Tharos (30. 4. 2013 14:21)

před 7 lety

David Grudl
Nette Core | 7148
+
0
-

Aha, takže ony jsou vody, kde je private injection nesmysl, a zároveň vody, kde je fajn? ;-)) Tak pardon, předchozí post jsem upravil.

před 7 lety

hrach
Člen | 1818
+
0
-
  • Jestli je nejaka technika „necista“, pak je necista vzdy.
  • Z presenteru se zde dela svecena voda, to co neni jinde povoleno, jeho krtem se stava svate.

před 7 lety

Tharos
Člen | 1042
+
0
-

@dg: V podstatě to tak je, protože IMHO prostě záleží, co daná třída reprezentuje a jak se její instance používají…

Pro mě osobně je presenter specifický tím, že a) nikde nepotřebuji ručně vytvořit jeho instanci (jednotkové testy pro presentery nepíšu a v aplikaci mi ho vytváří tuším PresenterFactory), b) pracuje se s ním zvenčí jen vzácně.

Já jsem hodně línej a to DI datlování závislostí mě trápí (když píšu type hinty, dokumentační komentáře…). Vím, že to je prostě cena za DI. Ale existuje-li způsob, jak si od toho pomoci, neváhám leccos obětovat.

U „standardních tříd“ (tj. neplatí pro ně to, co píšu v prvním odstavci) je samozřejmě private property injection nemyslitelná praktika (potřebuji je umět ručně vytvořit) a public property injection minimálně pro mě taky (zapouzdření nehodlám obětovat). Bohužel u nich tedy nezbývá, než datlovat.

U presenterů (pro které platí první odstavec) bych ale do private property injection osobně šel, protože nevýhody, jaké to má, mě u presenterů prostě netrápí. Do public property injection bych nešel, protože takhle porušit zapouzdření bych se (třeba v týmu) bál.

Pro mě prostě presentery specifické jsou. :–P

Editoval Tharos (30. 4. 2013 14:57)

před 7 lety

Tharos
Člen | 1042
+
0
-

hrach napsal(a):

„necista“

Definuj mi pojem „nečistá“. :)

Řekněme, že private property injection přináší určité problémy. Já jsem si toho ale vědom a prostě tam, kde ho použiji, ty problémy akceptuji (protože to pro mě v daném kontextu prostě problémy nejsou :–P). Mám se v podstatě bez důvodu ochudit o pragmatické řešení? Jenom proto, že je to „nečisté“, i když to jsou v daném kontextu prázdná slova?

před 7 lety

Tharos
Člen | 1042
+
0
-

hrach napsal(a):

  • Jestli je nejaka technika „necista“, pak je necista vzdy.

Podle tohoto dogma by se tedy neměla naimplementovat ani public property injection.

před 7 lety

David Grudl
Nette Core | 7148
+
0
-

Tharos napsal(a):

U „standardních tříd“ (tj. neplatí pro ně to, co píšu v prvním odstavci) je samozřejmě private property injection nemyslitelná praktika (potřebuji je umět ručně vytvořit)

Měl by obecný DI kontejner podporovat nemyslitelné praktiky? Z jeho pohledu je služba jako služba.

U presenterů (pro které platí první odstavec) bych ale do private property injection osobně šel, protože nevýhody, jaké to má, mě u presenterů prostě netrápí. Do public property injection bych nešel, protože takhle porušit zapouzdření bych se (třeba v týmu) bál.

Říkáš, že „presenter specifický tím, že pracuje se s ním zvenčí jen vzácně.“ a máš obavy o zapouzdření (tedy ryze vnější faktor), dokonce ve prospěch nemyslitelné praktiky.

před 7 lety

Tharos
Člen | 1042
+
0
-

ad Nemyslytelné prakticky) Pro mě je pro jiné třídy než presentery nemyslitelná private i public property injection, která už je AFAIK naimplementovaná. Někdo jiný to může (a pravděpodobně i bude) mít postavené jinak. Celé je to o tom, jak DI kontejner používá konkrétní programátor, respektive tým.

ad Zapouzdření) To je prostě něco za něco. Já preferuji private členy se zapouzdřením a obětuji to, že si nevytvořím presenter ručně. Někdo jiný zase bude preferovat public členy s možností vytvořit si presenter ručně (třeba v testech?) a obětuje zapouzdření, takže na sebe vezme rizika z toho vyplývající (u presenterů ale vážně malá). Já bych se rád přiklonil k public verzi, ale prostě v ní osobně nevidím vůbec žádnou výhodu (možnost vytvoření instance presenteru ručně pro mě není výhoda – nepoužívám).

Editoval Tharos (30. 4. 2013 15:45)

před 7 lety

pekelnik
Člen | 468
+
0
-

@David Grudl: tady je ten kód :)

před 7 lety

SendiMyrkr
Člen | 29
+
0
-

Absolutně nechápu, proč by se měla takhle znásilňovat logika třídy. Private/Protected property má svoji jasnou viditelnost a to, že do ní někde nějak magicky vstříknu závislost jednak nepřinese nic pozitivního a druhak to bude pouze wtf pro nováčky a je úplně jedno jestli se to omezí jenom na presenter. Úplně vidim nováčky co zaplevelí fórum dotazy proč nemůžu přistupovat k týhle private závislosti z potomka když to Nette umí nastavit zvenku… A těch nováčků v OOP tu je dost. Pokud to někdo chce dělat je to jeho věc, ale v Nette by to podle mě být nemělo. Public property injection bych taky moc nepoužíval, jestli vůbec, ale aspoň tam mam zřejmý, z logiky vyplývající riziko, že si to omylem někde přepíšu.

Osobně preferuju constructor a setter injection(např. inject*) abych si sám mohl případně zvolit jestli ta která závislost je přepisovatelná nebo neni. U private/protected property bez kontaineru, nebo reflection, nevytvořim instanci a u public nebudu schopnej zajistit nepřepisovatelnost.

Trochu mi to připomíná situaci kdy někdo dostane zbraň(Reflection) a ustřelí si s ní hlavu(naruší zapouzdření)…

a teď do mě :)

před 7 lety

enumag
Člen | 2129
+
0
-

@SendiMyrkr: Pod tohle se s klidem podepíšu. :-)

před 7 lety

duke
Člen | 650
+
0
-

SendiMyrkr napsal:

Absolutně nechápu, proč by se měla takhle znásilňovat logika třídy. Private/Protected property má svoji jasnou viditelnost a to, že do ní někde nějak magicky vstříknu závislost jednak nepřinese nic pozitivního a druhak to bude pouze wtf pro nováčky a je úplně jedno jestli se to omezí jenom na presenter.

Kdyby to nepřineslo nic pozitivního, vůbec nikdo by o tom ani neuvažoval. To pozitivní, co by to přineslo, je „méně psaní“, což je něco, co mnoho programátorů ocení. Pro některé programátory (já k nim ale nepatřím) je to dokonce hlavní kritérium.

WTF pro nováčky to bude jen do chvíle, než se seznámí s dokumentací, kde to může být jasně vysvětleno a zdůvodněno, což lze ostatně říci o čemkoliv.

SendiMyrkr napsal:

Pokud to někdo chce dělat je to jeho věc, ale v Nette by to podle mě být nemělo.

Co se mě týče, jsem neutrální. Když to tam nebude, a bude tam jiný prostředek k dosažení téhož (např. inject* metody), obejdu se bez toho, byť s tím budu mít „více psaní“. Mám však za to, že by v Nette měl zůstat alespoň jeden praktický způsob jak injektovat závislosti, které chceme mít zapouzdřené, v případě, kdy není výhodné použít konstruktor injection (viz např. problém constructor hell s Nette presentery).

SendiMyrkr napsal:

Public property injection bych taky moc nepoužíval, jestli vůbec, ale aspoň tam mam zřejmý, z logiky vyplývající riziko, že si to omylem někde přepíšu.

Nejde jen o riziko přepsání, které lze eliminovat (viz řešení @dg pomocí triku s unset). Problém s public property je také v tom, že kdokoli si na danou službu může sáhnout zvenčí a např. ji pozměnit (změnit její nastavení, atp.), což se pak promítne v chování závislého objektu, který se o tom vůbec nedozví.

SendiMyrkr napsal:

Osobně preferuju constructor a setter injection(např. inject*) abych si sám mohl případně zvolit jestli ta která závislost je přepisovatelná nebo neni.

Konstruktor injection asi preferujeme téměř všichni. Setter injection vnímám jako vhodnou pro nepovinné závislosti. Její formu využívající inject* metod pak jako variantu, která pracuje pouze s povinnými závislostmi. A zde se právě projeví ona nevýhodnost, a to tak, že povinnou injektáž zde zajišťuje kontejner (podobně jako zajišťuje injektáž do private property s anotací @inject pomocí reflexe v případě private property injection). U obou těchto případů lze tedy hovořit o závislosti také na kontejneru. Rozdíl mezi těmito dvěma přístupy je pak v tom, že v případě private property injection nemusím psát injektovací metodu, neboť kontejner si to řeší sám. Je to tedy komplexnější řešení. Že při tom používá praktiku, která není zcela čistá, je dle mého názoru posvěceno dobrým účelem a tím, že jinak to prostě nejde.

U private/protected property bez kontaineru, nebo reflection, nevytvořim instanci a u public nebudu schopnej zajistit nepřepisovatelnost.

Pokud budeš trvat na požadavku vytvořit ji bez kontejneru, tak ji vytvoříš tak, jak je to možné (tj. tak, jak to dělá kontejner). Nepřepisovatelnost public property si budeš muset zajistit sám na úrovni daného objektu (trik s unset) a nebo tak, že se toto stane přímo součástí Nette\Object, který budeš moct podědit.

SendiMyrkr napsal:

Trochu mi to připomíná situaci kdy někdo dostane zbraň(Reflection) a ustřelí si s ní hlavu(naruší zapouzdření)…

Toto není příliš trefné přirovnání. Zapouzdřenost objektu má smysl pro vytvořený objekt, nikoli pro objekt, který se teprve vytváří. Např. vůči konstruktoru žádné zapouzdření neexistuje (neboť sám konstruktor je uvnitř), a private property injection pouze supluje to, co by měl dělat konstruktor, ale z praktických důvodů je to nevýhodné řešit konstruktorem. Jsou proto jen dvě možnosti. Buď dovolit tomu, kdo provádí private property injection zapouzdření nerespektovat, a nebo se smířit s tím, že nebude moci plně suplovat konstruktor.

Editoval duke (2. 5. 2013 22:03)

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

duke napsal(a):

Setter injection vnímám jako vhodnou pro nepovinné závislosti. Její formu využívající inject* metod pak jako variantu, která pracuje pouze s povinnými závislostmi. A zde se právě projeví ona nevýhodnost, a to tak, že povinnou injektáž zde zajišťuje kontejner

Za to, že někdo uvnitř objektu nekontroluje, že inject* byly zavolány jenom jednou a že vůbec byly zavolány nemůže container a nevzniká tím závislost na containeru. To je prostě chyba té konkrétní třídy.

… U obou těchto případů lze tedy hovořit o závislosti také na kontejneru.

Nesouhlasím :) viz výše

Pokud budeš trvat na požadavku vytvořit ji bez kontejneru, tak ji vytvoříš tak, jak je to možné (tj. tak, jak to dělá kontejner).

Psát takový kód, aby mi šlo vytvořit objekt jen pomocí reflexe je dost absurdní :)

Zapouzdřenost objektu má smysl pro vytvořený objekt, nikoli pro objekt, který se teprve vytváří.

Na to jsi prosím pěkně přišel jak?

Např. vůči konstruktoru žádné zapouzdření neexistuje (neboť sám konstruktor je uvnitř)

Konstruktor je přeci součástí třídy, tedy tohle nedává vůbec smysl.

před 7 lety

Šaman
Člen | 2438
+
0
-

Připadá mi to že už trochu flejmujem. Z diskuze vyplývá:

  • inject pomocí property je pro obecné závislosti nečistý (porušuje zapouzdření anebo je to magické jak Gandalfova hůl, vysoké riziko WTF efektu).
  • setter injection půjde použít vždycky (jen je to víc psaní), ve většině případů se doporučuje construct injection (problém může být s presentery).
  • inject* metody, i přes jejich nevýhody dost lidí používá, já bych je nerušil.
  • property injection, i přes jeho nevýhody, by dost lidí přivítalo. Jen bych poprosil nedávejte ho do tutoriálů.

Vypadá to, že jediná možnost jak zjistit víc bude povolit obě možnosti (*inject i property) a za rok si o tom promluvit znovu. Vzhledem ke snaze omezit magický faktor Nette bych hlasoval spíš pro public property injection.

před 7 lety

snake.aas
Člen | 25
+
0
-

Čím víc sleduju tohle téma, tak tu prostě nevidím žádné nejmenší zlo.

Inject do private se mi nelíbí (závislost na containeru, resp. čemkoliv jiném co mi musí zajistit integritu objektu), z API se dozvím leda houbeles a ne závislosti.

Public property se mi nelíbí už vůbec, protože nelze zajistit, že mi to nikdo nepřepíše, nenastaví jinak.

Davidovo řešení s unset mi přijde hodně zajímavé, ale určitě bych to nedával do Nette\Object.
Souhlasím s tím, že tohle by se mělo řešit pouze pro presentery, protože všude jinde použiju konstruktor!
A taky netuším, co by se stalo, kdybych se uklepl v anotaci @inject
Budu mít nekorektní objekt? Spadne mi to na vyjímce? Stane se něco úplně jiného? A zjistím to vůbec nějak jinak než „proč mi to sakra nejede?“

Kdyby tak jen PHP mělo normálně řešené properties, to by bylo krásně na světě…

před 7 lety

Šaman
Člen | 2438
+
0
-

Nejmenší zlo a křišťálově čistý kód získáš za trochu mámahy navíc. Použiješ obyčejný setter (případně si u něho budeš kontrolovat že nepřepíše jednou nastavenou hodnotu) a v configu si při vytváření objektu nastavíš v sekci setup co potřebuješ.

Když se překlepneš u inject*, jsi na tom podobně, jako když se překlepneš v anotaci. Nic ti nezařve, ale pokud testuješ, dozvíš se to.

A propo, pokud se nepletu, tak poslední dobou mají presentery jediný, nehezký, parametr – celý kontejner. Co vlastně brání použití konstruktoru i u presenterů?

před 7 lety

mkoubik
Generous Backer | 731
+
0
-

Šaman napsal(a):
A propo, pokud se nepletu, tak poslední dobou mají presentery jediný, nehezký, parametr – celý kontejner. Co vlastně brání použití konstruktoru i u presenterů?

V dev verzi nic, $this->context se používá jen v getContext() a getService() a konstruktor je prázdný.

před 7 lety

llook
Člen | 411
+
0
-

Co vlastně brání použití konstruktoru i u presenterů?

Že mívají těch závislostí hodně a na různých úrovních (např. BasePresenter má nějaké závislosti, Module\BasePresenter další a nakonec Module\ConcretePresenter ještě další). Když se změní závislosti BasePresenteru, tak musíš upravit konstruktory všech jeho potomků.

Bylo by možné závislosti abstraktních tříd nějak zapouzdřovat, bylo by to ale víc psaní:

class BasePresenter extends Presenter {
	function __construct(BasePresenterDependencies $baseDep) {
		$this->user = $baseDep->user;
		//atd...
	}
}
class ConcretePresenter extends BasePresenter {
	function __construct(BasePresenterDependencies $baseDep, ConcreteModel $model) {
		parent::__construct($baseDep);
		$this->model = $model;
	}
}

před 7 lety

duke
Člen | 650
+
0
-

Filip Procházka napsal:

duke napsal:

Setter injection vnímám jako vhodnou pro nepovinné závislosti. Její formu využívající inject* metod pak jako variantu, která pracuje pouze s povinnými závislostmi. A zde se právě projeví ona nevýhodnost, a to tak, že povinnou injektáž zde zajišťuje kontejner

Za to, že někdo uvnitř objektu nekontroluje, že inject* byly zavolány jenom jednou a že vůbec byly zavolány nemůže container a nevzniká tím závislost na containeru. To je prostě chyba té konkrétní třídy.

Mluvil jsem o zajišťování povinné injektáže (tj. o jejím provádění), nikoli o následné kontrole toho, že proběhla, či že proběhla právě jednou. Tyto kontroly jsou skutečně zodpovědností konkrétních tříd. Zajišťování dodání povinných závislostí je ale zodpovědností toho, kdo danou třídu vytváří. A zda jde o závislosti, které se předávají konstruktorem, či skrze metodu která splňuje nějakou jmennou konvenci (např. inject*), či skrze automatizovanou injektáž do property, která má anotaci @inject, je jen technický detail. Jakými prostředky se to uskuteční (např. v případě private property pomocí reflexe, protože jinak to nejde), je již druhotný problém.

Filip Procházka napsal:

duke napsal:

… U obou těchto případů lze tedy hovořit o závislosti také na kontejneru.

Nesouhlasím :) viz výše

Možná jsem to příliš zkonkrétnil s tím kontejnerem. Závislost tu vzniká v tom smylu, že ten, kdo chce dané třídy vytvářet, musí vědět, že má v jednom případě zavolat všechny inject* metody a v druhém případě naplnit všechny properties s anotací @inject. Přesněji řečeno tu tedy vzniká závislost na jakémsi protokolu vytváření (tento protokol pak zpravidla implementuje právě kontejner).

Filip Procházka napsal:

duke napsal:

Pokud budeš trvat na požadavku vytvořit ji bez kontejneru, tak ji vytvoříš tak, jak je to možné (tj. tak, jak to dělá kontejner).

Psát takový kód, aby mi šlo vytvořit objekt jen pomocí reflexe je dost absurdní :)

Absurdní je pouze to, co nemá účel.

Filip Procházka napsal:

duke napsal:

Zapouzdřenost objektu má smysl pro vytvořený objekt, nikoli pro objekt, který se teprve vytváří.

Na to jsi prosím pěkně přišel jak?

Uznávám, tady jsem trochu přestřelil. Nicméně pořád si myslím, že jednorázové porušení zapouzdřenosti při vytváření třídy pomocí reflexe v případě, kdy to třída očekává (uvedením dané anotace), je přijatelné, neboť účel, který to plní (vytvoření objektu se zapouzdřenými závislostmi a více pohodlí pro programátora) je dobrý.

Filip Procházka napsal:

duke napsal:

Např. vůči konstruktoru žádné zapouzdření neexistuje (neboť sám konstruktor je uvnitř)

Konstruktor je přeci součástí třídy, tedy tohle nedává vůbec smysl.

Vždyť jsem to sám uvedl. Chceme prostě suplovat to, co má v ideálním případě dělat konstruktor, alternativními prostředky. Jenže k tomu, aby to bylo stejně mocné jako konstruktor, musíme těmto prostředkům dát i stejná prává přístupu. To splňují samy o sobě např. inject* metody, se kterými je ale zbytečně moc psaní. Pak je tu property injection, se kterou je méně psaní, ale toto řešení samo o sobě (bez použití reflexe) nedisponuje stejnými právy přístupu a proto nedokáže samo o sobě plně suplovat konstruktor.

A také bych se rád opravil/doplnil: I pro konstruktor existuje zapouzdření, a sice v případě použití dědičnosti.

před 7 lety

castamir
Člen | 630
+
0
-

A také bych se rád opravil/doplnil: I pro konstruktor existuje zapouzdření, a sice v případě použití dědičnosti.

@duke: WTF?!? Kontruktor je jen další metoda objektu, která má nastavenou svou viditelnost (public nebo méně častěji protected či private). Nic víc v tom nehledej.


Už to tady jednou padlo, ale raději to zopakuju. Injection do public property není úplně dostatečný mechanismus pro odlehčení konstruktoru. Povolí-li se pouze injektáž public property, znemožní se zapouzdření, povolí-li se vstříknutí do private/protected properties, poruší se tím zapouzření objektu. Ani jedna varianta se mi nelíbí.

Inject* metody naproti tomu potřebnou funkcionalitu (inject do private/protected property) umožňují, ale jejich nevýhodou je více psaní. Umožňují však nepřepisovatelnost (final), což je další bonus. A že může být závislostí více? Mě to nevadí. Navíc není potřeba nutně psát jednu metodu pro každou vstříknutou závislost, ale lze jich mít v jedné inject metodě více (podobně jako v konstruktoru), ale zároveň mi odpadne problém s voláním parent::.

Nezlobte se na mě, ale tahle celá debata je pro mě zcela nesmyslná. Inject metody mají své využití a inject do properties jejich místo nahradit nedokáže. Chcete míň psaní a přidat další WTF faktor s bad practise jako bonus? V takovém případě inject do public property povolte. Inject* metody ale rozhodně nerušte.

před 7 lety

duke
Člen | 650
+
0
-

castamir napsal:

A také bych se rád opravil/doplnil: I pro konstruktor existuje zapouzdření, a sice v případě použití dědičnosti.

@duke: WTF?!? Kontruktor je jen další metoda objektu, která má nastavenou svou viditelnost (public nebo méně častěji protected či private). Nic víc v tom nehledej.

Měl jsem na mysli to, že i pro konstruktor mohou být některé věci zapouzdřeny (např. private properties jeho předka). Že i samotný konstruktor má svou viditelnost je mi samozřejmě známo, ale to není to, na co jsem chtěl poukázat.

castamir napsal:

Už to tady jednou padlo, ale raději to zopakuju. Injection do public property není úplně dostatečný mechanismus pro odlehčení konstruktoru. Povolí-li se pouze injektáž public property, znemožní se zapouzdření, povolí-li se vstříknutí do private/protected properties, poruší se tím zapouzření objektu. Ani jedna varianta se mi nelíbí.

Máš pravdu, ale podívej se na to i očima těch, kterým se nelíbí více psaní, než je nezbytně nutné.

castamir napsal:

Inject* metody naproti tomu potřebnou funkcionalitu (inject do private/protected property) umožňují, ale jejich nevýhodou je více psaní. Umožňují však nepřepisovatelnost (final), což je další bonus. A že může být závislostí více? Mě to nevadí. Navíc není potřeba nutně psát jednu metodu pro každou vstříknutou závislost, ale lze jich mít v jedné inject metodě více (podobně jako v konstruktoru), ale zároveň mi odpadne problém s voláním parent::.

Všechno, co dokáží inject* metody, dokáže i property injection, pokud použiješ reflexi (k obejití překážek, které mají jinde svůj význam, ale zde ne). A nad to ti odpadne nejen volání parent:: ale i psaní celé/celých inject* metod. Bazírovat na respektování těchto překážek i zde je IMHO kontraproduktivní.

Nezlobte se na mě, ale tahle celá debata je pro mě zcela nesmyslná. Inject metody mají své využití a inject do properties jejich místo nahradit nedokáže. Chcete míň psaní a přidat další WTF faktor s bad practise jako bonus? V takovém případě inject do public property povolte. Inject* metody ale rozhodně nerušte.

Pro mě osobně není private property injection o nic víc WTF než inject* metody. A za bad practise bych to považoval pouze tam, kde je praktičtější použít konstruktor injection.

před 7 lety

SendiMyrkr
Člen | 29
+
0
-

duke napsal:

castamir napsal:

Už to tady jednou padlo, ale raději to zopakuju. Injection do public property není úplně dostatečný mechanismus pro odlehčení konstruktoru. Povolí-li se pouze injektáž public property, znemožní se zapouzdření, povolí-li se vstříknutí do private/protected properties, poruší se tím zapouzření objektu. Ani jedna varianta se mi nelíbí.

Máš pravdu, ale podívej se na to i očima těch, kterým se nelíbí více psaní, než je nezbytně nutné.

Ti mají možnost si kód upravit. To, že se někomu nelíbí více psaní je jeho vlastní postoj kterým si ospravedlní hack. Ale znovu opakuji, nevidím jediný, byť sebemenší důvod, proč by takový hack měl být základní výbavou…

duke napsal:
Pro mě osobně není private property injection o nic víc WTF než inject* metody. A za bad practise bych to považoval pouze tam, kde je praktičtější použít konstruktor injection.

Jenomže potenciální WTF u injection* se dá vyřešit komentářem u třídy, nebo ustavením úzu v dokumentaci balíčku. Private property vyžaduje použítí reflexe. Potřebuji pak mít helper jenom na to abych vůbec dokázal vytvořit instanci, to je přece zbytečné. Navíc u private property nejsem z veřejného API schopen poznat co vlastně ta třída potřebuje.

Znovu opakuji svůj názor, private property injection je zásadním porušením jednoho ze základních pravidel, a jako takový by měl být pouze volitelnou částí, nikoli základní součástí Nette.

před 7 lety

duke
Člen | 650
+
0
-

SendiMyrkr napsal:

duke napsal:
Máš pravdu, ale podívej se na to i očima těch, kterým se nelíbí více psaní, než je nezbytně nutné.

Ti mají možnost si kód upravit. To, že se někomu nelíbí více psaní je jeho vlastní postoj kterým si ospravedlní hack. Ale znovu opakuji, nevidím jediný, byť sebemenší důvod, proč by takový hack měl být základní výbavou…

I ty máš možnost si kód upravit (či prostě jen tuto featuru nevyužívat). A to, že dáváš přednost ručnímu psaní kódu, který bude dělat něco, co by mohl automaticky řešit framework, jen aby ses vyhnul „hacku“, je také jen tvůj osobní postoj, kterým si tento masochismus ospravedlňuješ. Já zase nevidím jediný důvod, proč by to v základní výbavě být nemohlo.

SendiMyrkr napsal:

Jenomže potenciální WTF u injection* se dá vyřešit komentářem u třídy, nebo ustavením úzu v dokumentaci balíčku.

Totéž platí i pro private property injection.

SendiMyrkr napsal:

Private property vyžaduje použítí reflexe. Potřebuji pak mít helper jenom na to abych vůbec dokázal vytvořit instanci, to je přece zbytečné.

A co má být? To je takový problém použít helper? Navíc, jak vyplynulo z diskuse, používalo by se to téměř výhradně pro presentery, které ručně vytvářet v podstatě ani nepotřebuješ. A zbytečné je to úplně stejně jako je zbytečné psát inject metody.

SendiMyrkr napsal:

Navíc u private property nejsem z veřejného API schopen poznat co vlastně ta třída potřebuje.

Čemu říkáš veřejné API? Co se mě týče, je deklarace čehokoli s anotací @inject (včetně private property) součástí veřejného API třídy.

SendiMyrkr napsal:

Znovu opakuji svůj názor, private property injection je zásadním porušením jednoho ze základních pravidel, a jako takový by měl být pouze volitelnou částí, nikoli základní součástí Nette.

Dodržování pravidel je sice hezká věc, ale jde také o to, zda jsou pravidla nastavena rozumně. Jak už tu kdosi napsal, když už porušujeme pravidla, je třeba vědět jaká a proč. Důležitá nejsou pravidla sama o sobě, ale to, jaké následky bude mít jejich dodržení či porušení.

Chceš-li tedy dokázat, že property injection je zlo, uveď příklad negativních následků, jaké by to mohlo mít. Říkat, že je to nečisté, hack, ee, atp. není argument. Já prozatím mohu uvést negativní důsledek toho, že se dá přednost inject* metodám. Tím negativním důsledkem je zbytečné znepřehlednění tříd těmito metodami, které by se daly nahradit stručnou a jasnou anotací, tj. zbytečné psaní obslužného kódu, které lze nahradit automatikou.

před 7 lety

norbe
Backer | 405
+
0
-

Ale znovu opakuji, nevidím jediný, byť sebemenší důvod, proč by takový hack měl být základní výbavou…

Já vidím jeden zásadní a sice že to tam David nepřidá (z mého pohledu naštestí).

Osobně jsem spíš schůdný k public, než že pak nějaký nováček bude brát nastavování private hodnot za zcela běžnou věc a hackovat kde co.

před 7 lety

Honza Marek
Člen | 1674
+
0
-

Ne, že bych vám chtěl rušit flejmování (i když…), ale nakonec jsem neodolal.

Shrnutí: pro inject do public, pro zachování inject metod, proti inject do private

  • Jistě i zastánci @inject do private property uznají, že je to tak trochu prasárna. Pak je úplně jedno, jestli prasečím jedním nebo druhým způsobem. Z tohoto pohledu private tedy žádné výhody nepřináší.
  • Na kolika místech zvenku provádíte přiřazení do presenteru? Já jen v testech nastavuju autoCanonicalize. Na nic jiného si nemůžu vzpomenout. Příležitostí pro to udělat špatné přiřazení do public property je tedy velice málo.
  • Možnost vytvořit presenter bez reflexe se hodí. Pokud by podpora @inject byla zadrátována v PresenterFactory, byla by mnohem větší práce vytvořit alternativní PresenterFactory. Např. v Mediu takovou máme, protože chceme mít všechny presentery jako služby. Argument s vytvářením testů presenteru už padl.
  • Inject metody bych chtěl zachovat jednak kvůli zpětné kompatibilitě, druhak pokud někdo chce mermomocí validovat injektované objekty, tak bych mu v tom nebránil.

před 7 lety

pekelnik
Člen | 468
+
0
-

@**Honza Marek:**

  1. Jistě i zastánci public property injection a inject metod uznají, že je to tak trochu prasárna ;) Pak je úplně jedno, jestli prasečím jedním nebo druhým způsobem. Z tohoto pohledu private property injection tedy přináší výhodu méně psaní oproti inject metodám a výhodu zapouzdření oproti public property injection.
  2. O „přiřazování věcí zvenku“ (aka DI) je tahle debata, čili argument, že toto není důležité kulhá alespoň na jednu nohu ;)
  3. Souhlasím, že vytvářet objekty bez reflexe se hodí. Taky nikdo nikoho nenutí aby to dělal jinak ;)
  4. Souhlasím – viz můj příspěvěk: … z důvodu zpětné kompatibility by inject metody měly zůstat funkční minimálně někam do verze 2.2. Nevadilo by mi kdyby Nette ve verzi 2.1 generovalo upozornění úrovně E_USER_DEPRECATED pro tyto metody.

a znovu bych chtěl zopakovat pro ty kteří to ještě nepochopili:

Veřejné API nemá s private property injection problém protože @property.

Editoval pekelnik (3. 5. 2013 12:38)

před 7 lety

Filip Procházka
Moderator | 4693
+
0
-

pekelnik napsal(a):

i zastánci public property injection a inject metod uznají, že je to tak trochu prasárna

Neuznají :) Property injection a setter injection jsou čisté DI praktiky. To že se zavedla konvence, že speciálně označené „vstupní body“ objektu se volají automaticky je jenom chytrý autowire, který ušetří psaní konfigurace. Nevzniká tím žádná závislost na konkrétním DI Containeru, naopak tím vzniká čitelnější api objektu (význam zprávy inject vs set).

Na druhou stranu, rozhodně bych inject*() metodu nepoužil v modelové třídě a nejspíš ani tu property injection. Ale né protože by to byla prasárna, ale protože jsem ještě nenarazil na konkrétní příklad, kde by se to opravdu hodilo.

Veřejné API nemá s private property injection problém protože @property.

Jenže to není deklarované veřejné api objektu pomocí jazykových konstruktů. Není to zpráva, na kterou by objekt uměl odpovědět = není to veřejné api. To je jako by ti někdo strčil ruku do zadku, udělal by si z tebe maňáska a prohlásil to za standard :)

Editoval Filip Procházka (3. 5. 2013 13:08)

před 7 lety

Tharos
Člen | 1042
+
0
-

Snad v každém druhém příspěvku se tu skloňují obraty čistá praktika a prasárna. :) Dokážete někdo definovat, co znamenají? ;)

U svého vlastního kódu chci, aby v první řadě spolehlivě dělal to, co má. Dále chci, aby jeho psaní bylo efektivní (prostě abych se neupsal), aby šel dobře testovat, nebyl ze své podstaty náchylný k chybám, neopakovala se v něm logika, byl dobře čitelný a byl dobře rozšiřitelný.

Aplikuji-li tyhle požadavky, mně osobně prostě vychází private property injection oproti public property injection lépe. Ale vážně už to nikomu necpu…

Je mi vcelku fuk, jestli podle vyznání programátora XYZ píšu „čistý kód“ nebo „prasím“. :) Já nechci psát čistý ani špinavý/WTF/funky/whatever kód… Chci prostě jenom psát kód, který splňuje výše uvedená kritéria (takový totiž optimálním způsobem vede k mému nebo klientovo cíli).

před 7 lety

duke
Člen | 650
+
0
-

Honza Marek napsal:

Jistě i zastánci @inject do private property uznají, že je to tak trochu prasárna.

Spíše než prasárna je to obcházení překážek, které jinde mají své opodstatnění, ale zde nikoli. Jistě by bylo lepší, kdyby na to bylo v PHP myšleno, a nemuselo se to řešit reflexí, ale aspoň že je ta reflexe.

Honza Marek napsal:

Pak je úplně jedno, jestli prasečím jedním nebo druhým způsobem.

Že obcházím v daném kontextu nerozumné pravidlo, ještě neznamená, že ho (nebo jiná pravidla) budu obcházet vždy. Vždyť hlavní motivací, proč použít private property je právě snaha zachovat zapouzdřenost tam, kde to má smysl. Čili účelem je naopak zabránit prasení (vytváření špatně zapouzdřených objektů).

Honza Marek napsal:

Z tohoto pohledu private tedy žádné výhody nepřináší.

To jako měla být objektivní analýza výhod a nevýhod?

Honza Marek napsal:

Příležitostí pro to udělat špatné přiřazení do public property je tedy velice málo.

Již Murphy věděl, že může-li se něco pokazit (špatně přiřadit), tak se to také pokazí. Psát nezapouzdřené objekty považuju osobně za daleko větší prasárnu než používání private property injection.

Honza Marek napsal:

Možnost vytvořit presenter bez reflexe se hodí. Pokud by podpora @inject byla zadrátována v PresenterFactory, byla by mnohem větší práce vytvořit alternativní PresenterFactory.

Myslím, že poněkud přeháníš. A i kdyby to bylo bůh ví jak pracné, tu svou alternativní PresenterFactory napíšeš jen jednou. Navíc na to může být pamatováno a implementováno tak, aby to šlo snadno rozšířit/přetížit.

Honza Marek napsal:

Inject metody bych chtěl zachovat jednak kvůli zpětné kompatibilitě, druhak pokud někdo chce mermomocí validovat i njektované objekty, tak bych mu v tom nebránil.

Já bych je také alespoň zatím nerušil. Ať si každý vybere, jestli chce psát inject* metody nebo jednoduché anotace. Co se validace injektáže týče, tak u private property injection to lze řešit automatizovaně, takže opět méně psaní.

Filip Procházka napsal:

Pekelnik napsal:
Veřejné API nemá s private property injection problém protože @property.

Jenže to není deklarované veřejné api objektu pomocí jazykových konstruktů. Není to zpráva, na kterou by objekt uměl odpovědět = není to veřejné api.

A co má být, že to není pomocí jazykových konstruktů? Komu to vadí a proč? Pokud bys byl v tomto přístupu důsledný, musel bys úplně zakázat používání anotací.

@Tharos Nelze než ve všem souhlasit.

před 7 lety

Honza Marek
Člen | 1674
+
0
-

duke napsal(a):

Spíše než prasárna je to obcházení překážek, které jinde mají své opodstatnění, ale zde nikoli.

Přemejšlim, jestli není ještě nějaká jiná a jednodušší cesta jak obejít překážku, že do property nelze přiřadit. Ha! Něco mě napadlo. Co takhle udělat tu property public, když už do ní chci přiřazovat?

před 7 lety

David Grudl
Nette Core | 7148
+
0
-

Pár poznámek:

  • Nikdo metody inject neruší. Úvodní post jen říkal, že selhala osvěta a používají se i tam, kde lze (a tudíž je záhodno) použít konstruktor.
  • Property injection je korektní a běžný způsob předávání závislostí, stejně jako setter nebo constructor injection.
  • Že PHP nedokáže řídit přístup k property je nedostatek PHP, se kterým nutno počítat, avšak se asi časem změní.
  • Jakékoliv hinty v kódu pro DI kontejner, např. anotace, jsou zlo. (sic!)