You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: best-practices/bg/inject-method-attribute.texy
+17-47Lines changed: 17 additions & 47 deletions
Original file line number
Diff line number
Diff line change
@@ -2,13 +2,20 @@
2
2
********************************
3
3
4
4
.[perex]
5
-
С помощта на конкретни примери ще разгледаме възможностите за предаване на зависимости на презентатори и ще обясним методите и атрибутите/анотациите на `inject`.
5
+
В тази статия ще се съсредоточим върху различните начини за предаване на зависимости на презентатори в рамката Nette. Ще сравним предпочитания метод, който е конструкторът, с други възможности, като например методи и атрибути на `inject`.
6
+
7
+
И за презентаторите предаването на зависимости чрез [конструктора |dependency-injection:passing-dependencies#Constructor Injection] е предпочитаният начин.
8
+
Въпреки това, ако създадете общ предшественик, от който другите презентатори наследяват (например BasePresenter), и този предшественик също има зависимости, възниква проблем, който наричаме [конструкторски ад |dependency-injection:passing-dependencies#Constructor hell].
9
+
Той може да бъде заобиколен с помощта на алтернативни методи, които включват инжектиране на методи и атрибути (анотации).
6
10
7
11
8
12
`inject*()` Методи .[#toc-inject-methods]
9
13
=========================================
10
14
11
-
В presenter, както и във всеки друг код, предпочитаният начин за предаване на зависимости е чрез използване на [конструктор |dependency-injection:passing-dependencies#Constructor Injection]. Въпреки това, ако presenter наследява от общ предшественик (например `BasePresenter`), по-добре е да се използват методите на `inject*()` в този предшественик. Това е специален случай на setter, при който методът започва с префикс `inject`. Това е така, защото запазваме конструктора свободен за потомците:
15
+
Това е форма на предаване на зависимости с помощта на [задаващи елементи |dependency-injection:passing-dependencies#Setter Injection]. Имената на тези задаващи елементи започват с префикса inject.
16
+
Nette DI автоматично извиква тези методи веднага след създаването на инстанцията на презентатора и им предава всички необходими зависимости. Следователно те трябва да бъдат декларирани като публични.
17
+
18
+
`inject*()` Методите могат да се разглеждат като вид разширение на конструктора в множество методи. Благодарение на това `BasePresenter` може да приема зависимости чрез друг метод и да остави конструктора свободен за своите наследници:
12
19
13
20
```php
14
21
abstract class BasePresenter extends Nette\Application\UI\Presenter
@@ -32,55 +39,18 @@ class MyPresenter extends BasePresenter
32
39
}
33
40
```
34
41
35
-
Основната разлика от setter е, че Nette DI автоматично извиква методите с тези имена в preenters веднага след създаването на инстанцията, като им предава всички необходими зависимости. Презентаторът може да съдържа няколко метода `inject*()`, като всеки метод може да има произволен брой параметри.
36
-
37
-
Изпълнението чрез конструктор не се препоръчва за общи предци, тъй като по време на унаследяването трябва да получите зависимостите на всички родителски предци и да ги предадете на `parent::__construct()`:
38
-
39
-
```php
40
-
abstract class BasePresenter extends Nette\Application\UI\Presenter
41
-
{
42
-
private Foo $foo;
43
-
44
-
public function __construct(Foo $foo)
45
-
{
46
-
$this->foo = $foo;
47
-
}
48
-
}
49
-
50
-
class MyPresenter extends BasePresenter
51
-
{
52
-
private Bar $bar;
53
-
54
-
public function __construct(Foo $foo, Bar $bar)
55
-
{
56
-
parent::__construct($foo); // това е усложнение
57
-
$this->bar = $bar;
58
-
}
59
-
}
60
-
```
61
-
62
-
Методите `inject*()` са полезни и когато главният файл [се състои от функции |presenter-traits] и всяка от тях изисква своя собствена зависимост.
42
+
Презентаторът може да съдържа произволен брой методи `inject*()` и всеки от тях може да има произволен брой параметри. Това е чудесно и за случаите, когато презентаторът е [съставен от черти |presenter-traits] и всяка от тях изисква своя собствена зависимост.
63
43
64
-
Може да се използва и анотацията `@inject`, но е важно да се помни, че капсулирането е нарушено.
65
44
45
+
`Inject` Атрибути .[#toc-inject-attributes]
46
+
===========================================
66
47
67
-
Анотации `Inject` .[#toc-inject-annotations]
68
-
============================================
69
-
70
-
В този случай свойството е анотирано като `@inject` в коментара към документацията. Типът може да бъде анотиран и в коментара на документацията, ако използвате PHP под версия 7.4.
71
-
72
-
```php
73
-
class MyPresenter extends Nette\Application\UI\Presenter
74
-
{
75
-
/** @inject */
76
-
public Cache $cache;
77
-
}
78
-
```
48
+
Това е форма на [инжектиране в свойствата |dependency-injection:passing-dependencies#Property Injection]. Достатъчно е да посочите кои свойства трябва да бъдат инжектирани и Nette DI автоматично предава зависимостите веднага след създаването на инстанцията на презентатора. За да ги вмъкнете, е необходимо да ги декларирате като публични.
79
49
80
-
От версия PHP 8.0 свойството може да бъде маркирано с атрибута `Inject`:
50
+
Свойствата се маркират с атрибут: (преди се използваше анотацията `/** @inject */`)
81
51
82
52
```php
83
-
use Nette\DI\Attributes\Inject;
53
+
use Nette\DI\Attributes\Inject; // вносът е важен тук
84
54
85
55
class MyPresenter extends Nette\Application\UI\Presenter
86
56
{
@@ -89,9 +59,9 @@ class MyPresenter extends Nette\Application\UI\Presenter
89
59
}
90
60
```
91
61
92
-
Отново, Nette DI автоматично ще предава зависимости на свойствата, анотирани по този начин в презентатора, веднага щом инстанцията бъде създадена.
62
+
Предимството на този метод за предаване на зависимостите е, че той е много икономичен за записване. С въвеждането на [промоцията на свойствата на конструктора |https://blog.nette.org/bg/php-8-0-p-len-pregled-na-novostite#toc-constructor-property-promotion] обаче използването на конструктора изглежда по-лесно.
93
63
94
-
Този метод има същите недостатъци като предаването на зависимости към публично свойство. Използва се в презентаторите, защото не усложнява кода и изисква минимално въвеждане.
64
+
От друга страна, този метод страда от същите недостатъци като предаването на зависимости в свойства като цяло: нямаме контрол върху промените в променливата, а в същото време променливата става част от публичния интерфейс на класа, което е нежелателно.
Copy file name to clipboardExpand all lines: best-practices/cs/inject-method-attribute.texy
+17-47Lines changed: 17 additions & 47 deletions
Original file line number
Diff line number
Diff line change
@@ -2,13 +2,20 @@ Metody a atributy inject
2
2
************************
3
3
4
4
.[perex]
5
-
Na konkrétních případech si přiblížíme možnosti předávání závislostí do presenterů a vysvětlíme si metody a atributy/anotace `inject`.
5
+
V tomto článku se zaměříme na různé způsoby předávání závislostí do presenterů v Nette frameworku. Porovnáme preferovaný způsob, kterým je konstruktor, s dalšími možnostmi, jako jsou metody a atributy `inject`.
6
+
7
+
I pro presentery platí, že předání závislostí pomocí [konstruktoru |dependency-injection:passing-dependencies#Předávání konstruktorem] je preferovaná cesta.
8
+
Pokud ale vytváříte společného předka, od kterého dědí ostatní presentery (např. `BasePresenter`), a tento předek má také závislosti, nastane problém, kterému říkáme [constructor hell |dependency-injection:passing-dependencies#Constructor hell].
9
+
Ten lze obejít pomocí alternativních cest, které představují metody a atributy (anotace) `inject`.
6
10
7
11
8
12
Metody `inject*()`
9
13
==================
10
14
11
-
V presenterech, stejně jako v každém jiném kódu, je preferovaný způsob předávání závislostí pomocí [konstruktoru |dependency-injection:passing-dependencies#Předávání konstruktorem]. Pokud však presenter dědí od společného předka (např. `BasePresenter`), je lepší v tomto předkovi použít metody `inject*()`. Jedná se o zvláštní případ setteru, kdy metoda začíná prefixem `inject`. Jeho použitím si totiž ponecháme konstruktor volný pro potomky:
15
+
Jde o formu předávání závislosti [setterem |dependency-injection:passing-dependencies#Předávání setterem]. Název těchto setterů začíná předponou `inject`.
16
+
Nette DI takto pojmenované metody automaticky zavolá hned po vytvoření instance presenteru a předá jim všechny požadované závislosti. Musí být tudíž deklarované jako public.
17
+
18
+
Metody `inject*()` lze považovat za jakési rozšíření konstruktoru do více metod. Díky tomu může `BasePresenter` převzít závislosti přes jinou metodu a ponechat konstruktor volný pro své potomky:
12
19
13
20
```php
14
21
abstract class BasePresenter extends Nette\Application\UI\Presenter
@@ -32,55 +39,18 @@ class MyPresenter extends BasePresenter
32
39
}
33
40
```
34
41
35
-
Základní rozdíl od setteru je ten, že Nette DI takto pojmenované metody v presenterech automaticky volá hned po vytvoření instance a předá jim všechny požadované závislosti. Metod `inject*()` může presenter obsahovat více a každá může mít libovolný počet parametrů.
36
-
37
-
Pokud bychom závislosti předávali předkům skrze jejich konstruktory, museli bychom ve všech potomcích získávat i jejich závislosti a předávat je do `parent::__construct()`, což komplikuje kód:
38
-
39
-
```php
40
-
abstract class BasePresenter extends Nette\Application\UI\Presenter
41
-
{
42
-
private Foo $foo;
43
-
44
-
public function __construct(Foo $foo)
45
-
{
46
-
$this->foo = $foo;
47
-
}
48
-
}
49
-
50
-
class MyPresenter extends BasePresenter
51
-
{
52
-
private Bar $bar;
53
-
54
-
public function __construct(Foo $foo, Bar $bar)
55
-
{
56
-
parent::__construct($foo); // tohle je komplikace
57
-
$this->bar = $bar;
58
-
}
59
-
}
60
-
```
61
-
62
-
Metody `inject*()` se hodí také v případech, kdy je presenter [složen z trait |presenter-traits] a každá z nich si vyžádá vlastní závislost.
42
+
Metod `inject*()` může presenter obsahovat libovolný počet a každá může mít libovolný počet parametrů. Skvěle se hodí také v případech, kdy je presenter [složen z trait |presenter-traits] a každá z nich si žádá vlastní závislost.
63
43
64
-
Je také možné použít anotaci `@inject`, je však třeba mít na paměti, že dojde k porušení zapouzdření.
65
44
45
+
Atributy `Inject`
46
+
=================
66
47
67
-
Anotace `inject`
68
-
================
69
-
70
-
Jedná se o automatické předávání závislosti do veřejné členské proměnné presenteru, která je označená anotací `@inject` v dokumentačním komentáři. Typ závislosti je možné uvést také v dokumentačním komentáři, pokud používáte PHP nižší než 7.4.
71
-
72
-
```php
73
-
class MyPresenter extends Nette\Application\UI\Presenter
74
-
{
75
-
/** @inject */
76
-
public Cache $cache;
77
-
}
78
-
```
48
+
Jde o formu [injektování do property |dependency-injection:passing-dependencies#Nastavením proměnné]. Stačí označit, do kterých proměnných se má injektovat, a Nette DI automaticky předá závislosti hned po vytvoření instance presenteru. Aby je mohl vložit, je nutné je deklarovat jako public.
79
49
80
-
Od PHP 8.0 lze proměnnou označit pomocí atributu `Inject`:
50
+
Properites označíme atributem: (dříve se používala anotace `/** @inject */`)
81
51
82
52
```php
83
-
use Nette\DI\Attributes\Inject;
53
+
use Nette\DI\Attributes\Inject; // import je důležitý
84
54
85
55
class MyPresenter extends Nette\Application\UI\Presenter
86
56
{
@@ -89,9 +59,9 @@ class MyPresenter extends Nette\Application\UI\Presenter
89
59
}
90
60
```
91
61
92
-
Nette DI opět takto anotovaným proměnným v presenteru automaticky předá závislosti hned po vytvoření instance.
62
+
Výhodou tohoto způsobu předávání závislostí byla velice úsporná podoba zápisu. Nicméně s příchodem [constructor property promotion |https://blog.nette.org/cs/php-8-0-kompletni-prehled-novinek#toc-constructor-property-promotion] se jeví snazší použít konstruktor.
93
63
94
-
Tento způsob má stejné nedostatky, jako předávání závislosti do veřejné proměnné. V presenterech se používá proto, že nekomplikuje kód a vyžaduje jen minimum psaní.
64
+
Naopak tento způsob trpí stejnými nedostatky, jako předávání závislosti do properites obecně: nemáme kontrolu nad změnami v proměnné a zároveň se proměnná stává součástí veřejného rozhraní třídy, což je nežádnoucí.
0 commit comments