Lazy objekty v PHP 8.4 a jejich využití v Nette DI

David Grudl
Nette Core | 8221
+
+11
-

PHP 8.4 přináší nativní podporu lazy objektů. Lazy objekt je speciální typ objektu, který odkládá svoji skutečnou inicializaci až do chvíle, kdy je potřeba – konkrétně když poprvé přistoupíme k některé jeho vlastnosti. Do té doby existuje jen jako „prázdná“ instance, která nezabírá zbytečné prostředky ani nevykonává potenciálně náročné operace z konstruktoru.

A právě tato vlastnost je skvělá pro DI kontejner v Nette. Ten běžně při startu aplikace vytváří celý strom závislostí – tedy všechny služby a jejich závislosti. To ale může být zbytečně náročné, protože ne všechny služby jsou v každém requestu skutečně potřeba.

V nové testovací verzi nette/di 3.2-dev lze zapnout lazy vytváření služeb pomocí jednoduché konfigurace:

di:
    lazy: true

Co to znamená v praxi? Když si necháte z kontejneru vytáhnout nějakou službu, třeba:

$database = $container->getByType(Database::class);

Dostanete lazy objekt, který vypadá jako normální instance Database, nepoznáte rozdíl, ale ve skutečnosti ještě nemá vytvořené připojení k databázi. K tomu dojde až v momentě, kdy s databází začnete skutečně pracovat:

$database->query('SELECT ...');  // zde teprve dojde k vytvoření připojení

Pokud v daném requestu databázi vůbec nepoužijete, ušetříte prostředky za její inicializaci. To může být významná optimalizace, zejména u větších aplikací s komplexním stromem závislostí.

Samozřejmě to má i své důsledky – případné chyby při vytváření služeb (třeba špatné přihlašovací údaje k databázi) se projeví až při prvním použití, ne hned při startu aplikace. To může být v některých případech výhoda, v jiných nevýhoda, podle konkrétního use-case.

Bude zajímavé sledovat, jaký dopad bude mít tato novinka na výkon aplikací v produkčním prostředí. Potenciál pro optimalizaci je zde značný.


Při implementaci jsem nejprve zvažoval, že by se lazy zapínalo pro jednotlivé služby. Pak mi došlo, že opravdu bomba to bude, když se to naopak zapne pro úplně všechny služby a následně umožní selektivě vypínat. Na interní PHP třídy to vliv nemá, ty nelze lazyloadovat.

Marek Bartoš
Nette Blogger | 1267
+
+5
-

Super funkce, těším se na smazání všech accesorů

Pak mi došlo, že opravdu bomba to bude, když se to naopak zapne pro úplně všechny služby a následně umožní selektivě vypínat.

A jak se to dá vypnout? V konfiguraci a v extension. Některé služby (např. obousměrných bridge pro Tracy a Monolog) nejspíš budu muset inicializovat ihned, aby se správně propojily.

Editoval Marek Bartoš (Včera 23:33)

David Grudl
Nette Core | 8221
+
+3
-

Dá se v definici služby uvést lazy: false