Změny generovaných továrniček v Nette DI 4.0

David Grudl
Nette Core | 8099
+
+10
-

V Nette 4.0 bych rád vymetl historické relikty a vylepšil věci, které vznikly postupným vývojem a dnes již nejsou aktuální nebo by se daly udělat lépe. Důležitá je vaše zpětná vazba, protože můžete věci používat způsobem, který nepředpokládám.

Postupným vývojem prošly i generované továrničky.

Verze 4.0 bude vyžadovat, aby metody get() nebo create() měly uvedený návratový typ (nativně, nikoliv anotací). To předpokládám už všichni stejně dávno používáte.

Rád bych vylepšil i syntax generovaných továrniček. Současná podoba:

services:
	fooFactory:
		implement: FooFactory
		create: Foo(%bar%, %lorem%)
		parameters: [string ipsum, ?Bar bar, ?int lorem: null]
		setup:
			- setIpsum(%ipsum%)

Co tady vidím jako problematické?

  1. název klíče factory, který prostě není úplně šťastně zvolený s ohledem na zavádějící význam v případě továrniček. Do verze DI 2.3 existoval klíč create, ale ten se neujal. Uvažuju nad pokusem o znovuvzkříšení jakožto aliasu, trojice sloves implement, create a setup mi připadá srozumitelnější.
  2. klíč parameters: z mého pohledu jde o historický relikt z doby, kdy ještě neexistovalo automatické předávání parametrů do konstruktoru, a který v dnešní době není potřeba. Pokud ano a používáte jej, napište prosím jak a proč.
  3. %parametry% ve create: použití stejné syntaxe pro parametry tovární metody definované v klíči parameters a pro globální parametry má na jedné straně svou logiku, na druhou stranu to může být matoucí. Myslím, že stejně jako v předchozím bodě jde o historický relikt, který nahradilo automatické předávání parametrů do konstruktoru. Ale možná se pletu, tak dejte opět vědět.
  4. %parametry% v setup: opět řeším stejnou syntaxi pro parametry tovární metody a globální parametry. Tady už se netýká konstruktoru, takže k automatickému předávání parametrů nedochází. Připadalo by mi lepší parametry zapisovat jako setIpsum($ipsum) a vyhnout se procentové syntaxi. A zároveň by nebylo potřeba vytvářet klíč parameters, jako nyní.

Výsledek by tedy mohl vypadat takto:

services:
	fooFactory:
		implement: FooFactory
		create: Foo     # případně Foo($bar, $lorem)
		setup:
			- setIpsum($ipsum)

Pokud v konfiguraci není klíč setup, lze používat i zkrácenou podobu:

services:
	fooFactory: FooFactory(Foo)

Tento zápis mi nepřipadal úplně srozumitelný, ale nenapadá mě, jak by šel vylepšit, takže je to asi věcí volby každého, zda zkratku použije nebo ne.

Felix
Nette Core | 1185
+
+2
-

Souhlasim. Dobry napad.

Pridal by jsi prosim jeste ukazky PHP kodu, jak vypada FooFactory a Foo? Myslim, ze by to pekne dokreslilo predstavu. I pro ostatni.

David Grudl
Nette Core | 8099
+
+1
-

Doplňuji:

class Foo
{
	public function __construct(Bar $bar, int $lorem = null)
	{
	}

	public function setIpsum(string $ipsum)
	{
	}
}

interface FooFactory
{
	function create(string $ipsum, ?Bar $bar, int $lorem = null): Foo;
}
Polki
Člen | 553
+
0
-
  1. souhlas – klíč factory ve mě evokuje, že se jedná o třídu továrny, ne o třídu, kterou má generovaná továrna tvořit. create mi přijde vhodnější.
  2. souhlas – Až do teď jsem nevěděl, že to existuje. První co mě napadlo, tak že by tím šly přepsat výchozí hodnoty daných parametrů, případně dynamicky přidávat další. Nenapadá mě ale případ, kde bych to využil
  3. souhlas – Parametry dodá buď přímo DI, nebo se automaticky předají z create metody továrny. Takže mi přijde zbytečné mít možnost si to definovat ještě zde, co se kam předává. Nikdy jsem nepoužil. Na předání globálního parametru používám arguments: [parameterFromConfig: %myParameter%], takže za mě není třeba umožňovat definovat předání parametru explicitně zde.
  4. souhlas – pro mě jsou sice parametry, které předávám do metody create povinné a tedy je cpu do konstruktoru. Setup používám jen když chci nastavit nepovinné parametry, které definuji v configu, takže já mám jasno, že v setup jsou vždy jen globální parametry. Rozumím tomu ale, že někdo má konstruktor co nejjednodušší a tedy spoustu parametrů si nastavuje nepovinně i když je vyžaduje metoda create a pro takové případy by se hodilo rozlišit, jestli se má předat globální parametr, nebo parametr funkce create.

Pokud jde o:

services:
	fooFactory: FooFactory(Foo)

co takto:

services:
	fooFactory: FooFactory(): Foo

Případně místo dvojtečky jiná konstrukce místo dvojtečky, která by připomínala návratovou hodnotu a nekolidovala s ostatními dvojtečkami?

jiri.pudil
Nette Blogger | 1028
+
+6
-

Asi moc nepřispěju do diskuse, protože jsem žádné takové divoké nastavování u továrniček nikdy nepotřeboval. I proto bych byl moc rád, aby zůstal zachován i ten úplně nejzkrácenější zápis:

services:
    - FooFactory

DI compiler si s tímhle vystačí a definici služby – na základě detekce rozhraní a reflexe create() metody – vygeneruje úplně správně dle očekávání. Nevidím potřebu duplikovat FooFactory(Foo) v configu, když už mám v kódu create(): Foo.

David Grudl
Nette Core | 8099
+
+7
-

Na nejzkracenějším zápise samozřejmě není potřeba nic měnit.

Milo
Nette Core | 1283
+
0
-

Namísto create mě napadlo generates, nebo provides, ale není to úplně přesné.

Pavel Kravčík
Člen | 1180
+
0
-

Vypadá to super!

Možná je poznámka – na první dobrou není jasný rozdíl mezi následujícím:

- {implement: FooFactory, arguments: [%peter%]}
- {implement: FooFactory, parameters: [%john%]}