Nette Documentation Preview

syntax
Pogosta vprašanja o DI (FAQ)
****************************


Ali je DI drugo ime za IoC? .[#toc-is-di-another-name-for-ioc]
--------------------------------------------------------------

*Inversion of Control* (IoC) je načelo, ki se osredotoča na način izvajanja kode - ali vaša koda sproži zunanjo kodo ali pa je vaša koda vključena v zunanjo kodo, ki jo nato pokliče.
IoC je širok koncept, ki vključuje [dogodke |nette:glossary#Events], tako imenovano [hollywoodsko načelo |application:components#Hollywood style] in druge vidike.
Sestavni deli tega koncepta so tudi tovarne, ki so del [pravila #3: Naj to opravi tovarna |introduction#Rule #3: Let the Factory Handle It], in predstavljajo inverzijo za operator `new`.

Pri *Dependency Injection* (DI) gre za to, kako en objekt ve za drug objekt, tj. za odvisnost. Gre za načrtovalski vzorec, ki zahteva izrecno posredovanje odvisnosti med objekti.

Tako lahko rečemo, da je DI posebna oblika IoC. Vendar pa vse oblike IoC niso primerne z vidika čistosti kode. Med anti-vzorce na primer uvrščamo vse tehnike, ki delajo z [globalnim stanjem |global state], ali tako imenovani [Service Locator |#What is a Service Locator].


Kaj je iskalnik storitev? .[#toc-what-is-a-service-locator]
-----------------------------------------------------------

Iskalnik storitev je alternativa vbrizganju odvisnosti. Deluje tako, da ustvari osrednje skladišče, v katerem so registrirane vse razpoložljive storitve ali odvisnosti. Ko objekt potrebuje odvisnost, jo zahteva od iskalnika storitev.

Vendar v primerjavi z vbrizgavanjem odvisnosti izgublja preglednost: odvisnosti niso neposredno posredovane objektom in jih zato ni mogoče zlahka prepoznati, zato je treba pregledati kodo, da bi odkrili in razumeli vse povezave. Tudi testiranje je bolj zapleteno, saj testiranim objektom ne moremo preprosto posredovati posnemovalnih objektov, temveč moramo to storiti prek iskalnika storitev. Poleg tega Service Locator moti načrtovanje kode, saj se morajo posamezni objekti zavedati njegovega obstoja, kar se razlikuje od vbrizgavanja odvisnosti, kjer objekti ne poznajo vsebnika DI.


Kdaj je bolje, da ne uporabljate DI? .[#toc-when-is-it-better-not-to-use-di]
----------------------------------------------------------------------------

Ni znanih težav, povezanih z uporabo oblikovnega vzorca Dependency Injection. Nasprotno, pridobivanje odvisnosti z globalno dostopnih lokacij povzroča [številne zaplete, |global-state] prav tako kot uporaba iskalnika storitev.
Zato je priporočljivo vedno uporabljati DI. To ni dogmatičen pristop, ampak preprosto ni bilo mogoče najti boljše alternative.

Vendar pa obstajajo določene situacije, v katerih si predmetov ne posredujemo med seboj in jih pridobivamo iz globalnega prostora. Na primer pri razhroščevanju kode, ko moramo izpisati vrednost spremenljivke na določeni točki programa, izmeriti trajanje določenega dela programa ali zabeležiti sporočilo.
V takih primerih, ko gre za začasna dejanja, ki bodo pozneje odstranjena iz kode, je upravičena uporaba globalno dostopnega odlagalnika, štoparice ali loggerja. Ta orodja navsezadnje ne sodijo v zasnovo kode.


Ali ima uporaba DI svoje slabosti? .[#toc-does-using-di-have-its-drawbacks]
---------------------------------------------------------------------------

Ali ima uporaba vrivanja odvisnosti kakšne slabosti, na primer večjo zapletenost pisanja kode ali slabšo zmogljivost? Kaj izgubimo, ko začnemo pisati kodo v skladu z DI?

DI ne vpliva na zmogljivost aplikacije ali pomnilniške zahteve. Delovanje vsebnika DI lahko igra vlogo, vendar je v primeru [Nette DI | nette-container] vsebnik sestavljen v čistem jeziku PHP, zato je njegova obremenitev med izvajanjem aplikacije v bistvu nična.

Pri pisanju kode je treba ustvariti konstruktorje, ki sprejemajo odvisnosti. V preteklosti je bilo to lahko zamudno, vendar je zaradi sodobnih IDE in [spodbujanja lastnosti konstruktorjev |https://blog.nette.org/sl/php-8-0-popoln-pregled-novic#toc-constructor-property-promotion] zdaj to vprašanje nekaj sekund. Konstruktorje lahko preprosto ustvarite z uporabo Nette DI in vtičnika PhpStorm z le nekaj kliki.
Po drugi strani pa ni treba pisati singletonov in statičnih točk dostopa.

Zaključimo lahko, da pravilno zasnovana aplikacija z uporabo DI ni niti krajša niti daljša v primerjavi z aplikacijo, ki uporablja singletone. Deli kode, ki delajo z odvisnostmi, se preprosto izločijo iz posameznih razredov in premaknejo na nova mesta, tj. v vsebnik DI in tovarne.


Kako prepisati starejšo aplikacijo na DI? .[#toc-how-to-rewrite-a-legacy-application-to-di]
-------------------------------------------------------------------------------------------

Prehod iz starejše aplikacije na vbrizgavanje odvisnosti je lahko zahteven proces, zlasti pri velikih in zapletenih aplikacijah. Pomembno je, da se tega procesa lotite sistematično.

- Pri prehodu na vbrizgavanje odvisnosti je pomembno, da vsi člani ekipe razumejo uporabljena načela in prakse.
- Najprej opravite analizo obstoječe aplikacije, da ugotovite ključne komponente in njihove odvisnosti. Ustvarite načrt, kateri deli bodo preoblikovani in v kakšnem vrstnem redu.
- Izvedite vsebnik DI ali, še bolje, uporabite obstoječo knjižnico, kot je Nette DI.
- Postopoma izboljšajte vsak del aplikacije, da bo uporabljal vbrizgavanje odvisnosti. To lahko vključuje spreminjanje konstruktorjev ali metod, da sprejmejo odvisnosti kot parametre.
- Spremenite mesta v kodi, kjer se ustvarjajo objekti odvisnosti, tako da odvisnosti namesto tega vbrizga vsebnik. To lahko vključuje uporabo tovarn.

Ne pozabite, da je prehod na vbrizgavanje odvisnosti naložba v kakovost kode in dolgoročno trajnost aplikacije. Čeprav je izvajanje teh sprememb morda zahtevno, mora biti rezultat čistejša, bolj modularna in zlahka testabilna koda, ki je pripravljena na prihodnje razširitve in vzdrževanje.


Zakaj ima sestava prednost pred dedovanjem? .[#toc-why-composition-is-preferred-over-inheritance]
-------------------------------------------------------------------------------------------------
Namesto [dedovanja |nette:introduction-to-object-oriented-programming#inheritance] je bolje uporabiti [sestavo |nette:introduction-to-object-oriented-programming#composition], saj omogoča ponovno uporabo kode, ne da bi morali skrbeti za posledice sprememb. Tako zagotavlja ohlapnejšo vezavo, pri kateri nam ni treba skrbeti, da bo sprememba neke kode povzročila potrebo po spremembi druge odvisne kode. Značilen primer je situacija, ki se imenuje [konstruktorski pekel |passing-dependencies#Constructor hell].


Ali se lahko vsebnik Nette DI Container uporablja zunaj sistema Nette? .[#toc-can-nette-di-container-be-used-outside-of-nette]
------------------------------------------------------------------------------------------------------------------------------

Absolutno. Nette DI Container je del sistema Nette, vendar je zasnovan kot samostojna knjižnica, ki se lahko uporablja neodvisno od drugih delov ogrodja. Preprosto jo namestite s programom Composer, ustvarite konfiguracijsko datoteko, ki opredeljuje vaše storitve, in nato z nekaj vrsticami kode PHP ustvarite vsebnik DI.
V svojih projektih lahko takoj začnete uporabljati prednosti vbrizgavanja odvisnosti (Dependency Injection).

V poglavju [Nette DI Container |nette-container] je opisano, kako je videti določen primer uporabe, vključno s kodo.


Zakaj je konfiguracija v datotekah NEON? .[#toc-why-is-the-configuration-in-neon-files]
---------------------------------------------------------------------------------------

NEON je preprost in lahko berljiv konfiguracijski jezik, ki je bil razvit v Nette za nastavljanje aplikacij, storitev in njihovih odvisnosti. V primerjavi z JSON ali YAML v ta namen ponuja veliko bolj intuitivne in prilagodljive možnosti. V jeziku NEON lahko na naraven način opišete povezave, ki jih v jezikih Symfony in YAML sploh ne bi bilo mogoče zapisati ali pa le z zapletenim opisom.


Ali razčlenjevanje datotek NEON upočasnjuje aplikacijo? .[#toc-does-parsing-neon-files-slow-down-the-application]
-----------------------------------------------------------------------------------------------------------------

Čeprav se datoteke NEON analizirajo zelo hitro, ta vidik ni pomemben. Razlog za to je, da se razčlenjevanje datotek izvede samo enkrat med prvim zagonom aplikacije. Po tem se ustvarja vsebniška koda DI, ki se shrani na disku in izvede za vsako naslednjo zahtevo brez potrebe po nadaljnjem razčlenjevanju.

Tako deluje v produkcijskem okolju. Med razvojem se datoteke NEON analizirajo vsakič, ko se spremeni njihova vsebina, kar zagotavlja, da ima razvijalec vedno na voljo posodobljen vsebnik DI. Kot je bilo že omenjeno, je dejansko razčlenjevanje vprašanje enega trenutka.


Kako lahko v svojem razredu dostopam do parametrov iz konfiguracijske datoteke? .[#toc-how-do-i-access-the-parameters-from-the-configuration-file-in-my-class]
--------------------------------------------------------------------------------------------------------------------------------------------------------------

Ne pozabite na [pravilo št. 1: Pustite, da vam ga posredujejo |introduction#Rule #1: Let It Be Passed to You]. Če razred zahteva informacije iz konfiguracijske datoteke, nam ni treba ugotavljati, kako dostopati do teh informacij, temveč jih preprosto zahtevamo - na primer prek konstruktorja razreda. Predajo pa izvedemo v konfiguracijski datoteki.

V tem primeru je `%myParameter%` nadomestek za vrednost parametra `myParameter`, ki bo posredovan konstruktorju `MyClass`:

```php
# config.neon
parameters:
	myParameter: Some value

services:
	- MyClass(%myParameter%)
```

Če želite posredovati več parametrov ali uporabiti samodejno povezovanje, je koristno, da [parametre zavijete v objekt |best-practices:passing-settings-to-presenters].


Ali Nette podpira vmesnik PSR-11 Container? .[#toc-does-nette-support-psr-11-container-interface]
-------------------------------------------------------------------------------------------------

Vmesnik Nette DI Container ne podpira PSR-11 neposredno. Če pa potrebujete interoperabilnost med vsebnikom Nette DI Container in knjižnicami ali ogrodji, ki pričakujejo vmesnik PSR-11 Container, lahko ustvarite [preprost adapter |https://gist.github.com/dg/7f02403bd36d9d1c73802a6268a4361f], ki služi kot most med Nette DI Container in PSR-11.

Pogosta vprašanja o DI (FAQ)

Ali je DI drugo ime za IoC?

Inversion of Control (IoC) je načelo, ki se osredotoča na način izvajanja kode – ali vaša koda sproži zunanjo kodo ali pa je vaša koda vključena v zunanjo kodo, ki jo nato pokliče. IoC je širok koncept, ki vključuje dogodke, tako imenovano hollywoodsko načelo in druge vidike. Sestavni deli tega koncepta so tudi tovarne, ki so del pravila #3: Naj to opravi tovarna, in predstavljajo inverzijo za operator new.

Pri Dependency Injection (DI) gre za to, kako en objekt ve za drug objekt, tj. za odvisnost. Gre za načrtovalski vzorec, ki zahteva izrecno posredovanje odvisnosti med objekti.

Tako lahko rečemo, da je DI posebna oblika IoC. Vendar pa vse oblike IoC niso primerne z vidika čistosti kode. Med anti-vzorce na primer uvrščamo vse tehnike, ki delajo z globalnim stanjem, ali tako imenovani Service Locator.

Kaj je iskalnik storitev?

Iskalnik storitev je alternativa vbrizganju odvisnosti. Deluje tako, da ustvari osrednje skladišče, v katerem so registrirane vse razpoložljive storitve ali odvisnosti. Ko objekt potrebuje odvisnost, jo zahteva od iskalnika storitev.

Vendar v primerjavi z vbrizgavanjem odvisnosti izgublja preglednost: odvisnosti niso neposredno posredovane objektom in jih zato ni mogoče zlahka prepoznati, zato je treba pregledati kodo, da bi odkrili in razumeli vse povezave. Tudi testiranje je bolj zapleteno, saj testiranim objektom ne moremo preprosto posredovati posnemovalnih objektov, temveč moramo to storiti prek iskalnika storitev. Poleg tega Service Locator moti načrtovanje kode, saj se morajo posamezni objekti zavedati njegovega obstoja, kar se razlikuje od vbrizgavanja odvisnosti, kjer objekti ne poznajo vsebnika DI.

Kdaj je bolje, da ne uporabljate DI?

Ni znanih težav, povezanih z uporabo oblikovnega vzorca Dependency Injection. Nasprotno, pridobivanje odvisnosti z globalno dostopnih lokacij povzroča številne zaplete, prav tako kot uporaba iskalnika storitev. Zato je priporočljivo vedno uporabljati DI. To ni dogmatičen pristop, ampak preprosto ni bilo mogoče najti boljše alternative.

Vendar pa obstajajo določene situacije, v katerih si predmetov ne posredujemo med seboj in jih pridobivamo iz globalnega prostora. Na primer pri razhroščevanju kode, ko moramo izpisati vrednost spremenljivke na določeni točki programa, izmeriti trajanje določenega dela programa ali zabeležiti sporočilo. V takih primerih, ko gre za začasna dejanja, ki bodo pozneje odstranjena iz kode, je upravičena uporaba globalno dostopnega odlagalnika, štoparice ali loggerja. Ta orodja navsezadnje ne sodijo v zasnovo kode.

Ali ima uporaba DI svoje slabosti?

Ali ima uporaba vrivanja odvisnosti kakšne slabosti, na primer večjo zapletenost pisanja kode ali slabšo zmogljivost? Kaj izgubimo, ko začnemo pisati kodo v skladu z DI?

DI ne vpliva na zmogljivost aplikacije ali pomnilniške zahteve. Delovanje vsebnika DI lahko igra vlogo, vendar je v primeru Nette DI vsebnik sestavljen v čistem jeziku PHP, zato je njegova obremenitev med izvajanjem aplikacije v bistvu nična.

Pri pisanju kode je treba ustvariti konstruktorje, ki sprejemajo odvisnosti. V preteklosti je bilo to lahko zamudno, vendar je zaradi sodobnih IDE in spodbujanja lastnosti konstruktorjev zdaj to vprašanje nekaj sekund. Konstruktorje lahko preprosto ustvarite z uporabo Nette DI in vtičnika PhpStorm z le nekaj kliki. Po drugi strani pa ni treba pisati singletonov in statičnih točk dostopa.

Zaključimo lahko, da pravilno zasnovana aplikacija z uporabo DI ni niti krajša niti daljša v primerjavi z aplikacijo, ki uporablja singletone. Deli kode, ki delajo z odvisnostmi, se preprosto izločijo iz posameznih razredov in premaknejo na nova mesta, tj. v vsebnik DI in tovarne.

Kako prepisati starejšo aplikacijo na DI?

Prehod iz starejše aplikacije na vbrizgavanje odvisnosti je lahko zahteven proces, zlasti pri velikih in zapletenih aplikacijah. Pomembno je, da se tega procesa lotite sistematično.

  • Pri prehodu na vbrizgavanje odvisnosti je pomembno, da vsi člani ekipe razumejo uporabljena načela in prakse.
  • Najprej opravite analizo obstoječe aplikacije, da ugotovite ključne komponente in njihove odvisnosti. Ustvarite načrt, kateri deli bodo preoblikovani in v kakšnem vrstnem redu.
  • Izvedite vsebnik DI ali, še bolje, uporabite obstoječo knjižnico, kot je Nette DI.
  • Postopoma izboljšajte vsak del aplikacije, da bo uporabljal vbrizgavanje odvisnosti. To lahko vključuje spreminjanje konstruktorjev ali metod, da sprejmejo odvisnosti kot parametre.
  • Spremenite mesta v kodi, kjer se ustvarjajo objekti odvisnosti, tako da odvisnosti namesto tega vbrizga vsebnik. To lahko vključuje uporabo tovarn.

Ne pozabite, da je prehod na vbrizgavanje odvisnosti naložba v kakovost kode in dolgoročno trajnost aplikacije. Čeprav je izvajanje teh sprememb morda zahtevno, mora biti rezultat čistejša, bolj modularna in zlahka testabilna koda, ki je pripravljena na prihodnje razširitve in vzdrževanje.

Zakaj ima sestava prednost pred dedovanjem?

Namesto dedovanja je bolje uporabiti sestavo, saj omogoča ponovno uporabo kode, ne da bi morali skrbeti za posledice sprememb. Tako zagotavlja ohlapnejšo vezavo, pri kateri nam ni treba skrbeti, da bo sprememba neke kode povzročila potrebo po spremembi druge odvisne kode. Značilen primer je situacija, ki se imenuje konstruktorski pekel.

Ali se lahko vsebnik Nette DI Container uporablja zunaj sistema Nette?

Absolutno. Nette DI Container je del sistema Nette, vendar je zasnovan kot samostojna knjižnica, ki se lahko uporablja neodvisno od drugih delov ogrodja. Preprosto jo namestite s programom Composer, ustvarite konfiguracijsko datoteko, ki opredeljuje vaše storitve, in nato z nekaj vrsticami kode PHP ustvarite vsebnik DI. V svojih projektih lahko takoj začnete uporabljati prednosti vbrizgavanja odvisnosti (Dependency Injection).

V poglavju Nette DI Container je opisano, kako je videti določen primer uporabe, vključno s kodo.

Zakaj je konfiguracija v datotekah NEON?

NEON je preprost in lahko berljiv konfiguracijski jezik, ki je bil razvit v Nette za nastavljanje aplikacij, storitev in njihovih odvisnosti. V primerjavi z JSON ali YAML v ta namen ponuja veliko bolj intuitivne in prilagodljive možnosti. V jeziku NEON lahko na naraven način opišete povezave, ki jih v jezikih Symfony in YAML sploh ne bi bilo mogoče zapisati ali pa le z zapletenim opisom.

Ali razčlenjevanje datotek NEON upočasnjuje aplikacijo?

Čeprav se datoteke NEON analizirajo zelo hitro, ta vidik ni pomemben. Razlog za to je, da se razčlenjevanje datotek izvede samo enkrat med prvim zagonom aplikacije. Po tem se ustvarja vsebniška koda DI, ki se shrani na disku in izvede za vsako naslednjo zahtevo brez potrebe po nadaljnjem razčlenjevanju.

Tako deluje v produkcijskem okolju. Med razvojem se datoteke NEON analizirajo vsakič, ko se spremeni njihova vsebina, kar zagotavlja, da ima razvijalec vedno na voljo posodobljen vsebnik DI. Kot je bilo že omenjeno, je dejansko razčlenjevanje vprašanje enega trenutka.

Kako lahko v svojem razredu dostopam do parametrov iz konfiguracijske datoteke?

Ne pozabite na pravilo št. 1: Pustite, da vam ga posredujejo. Če razred zahteva informacije iz konfiguracijske datoteke, nam ni treba ugotavljati, kako dostopati do teh informacij, temveč jih preprosto zahtevamo – na primer prek konstruktorja razreda. Predajo pa izvedemo v konfiguracijski datoteki.

V tem primeru je %myParameter% nadomestek za vrednost parametra myParameter, ki bo posredovan konstruktorju MyClass:

# config.neon
parameters:
	myParameter: Some value

services:
	- MyClass(%myParameter%)

Če želite posredovati več parametrov ali uporabiti samodejno povezovanje, je koristno, da parametre zavijete v objekt.

Ali Nette podpira vmesnik PSR-11 Container?

Vmesnik Nette DI Container ne podpira PSR-11 neposredno. Če pa potrebujete interoperabilnost med vsebnikom Nette DI Container in knjižnicami ali ogrodji, ki pričakujejo vmesnik PSR-11 Container, lahko ustvarite preprost adapter, ki služi kot most med Nette DI Container in PSR-11.