Podajanje odvisnosti
Argumente ali „odvisnosti“ v terminologiji DI lahko razredom posredujete na naslednje glavne načine:
- posredovanje s konstruktorjem
- posredovanje z metodo (imenovano setter)
- z nastavitvijo lastnosti
- z metodo, anotacijo ali atributom inject
Različne različice bomo zdaj ponazorili s konkretnimi primeri.
Vbrizgavanje konstruktorjev
Odvisnosti se konstruktorju ob ustvarjanju predmeta posredujejo kot argumenti:
Ta oblika je uporabna za obvezne odvisnosti, ki jih razred nujno potrebuje za delovanje, saj brez njih primerka ni mogoče ustvariti.
Od različice PHP 8.0 lahko uporabimo krajšo obliko zapisa (constructor property promotion), ki je funkcionalno enakovredna:
Od PHP 8.1 lahko lastnost označimo z zastavico readonly
, ki izjavlja, da se vsebina lastnosti ne bo
spremenila:
Kontejner DI samodejno posreduje odvisnosti konstruktorju z uporabo samodejnega povezovanja. Argumente, ki jih ni mogoče posredovati na ta način (npr. nize, številke, logične vrednosti), zapiše v konfiguracijo.
Konstruktorski pekel
Izraz konstruktorski pekel se nanaša na situacijo, ko potomec podeduje od starševskega razreda, katerega konstruktor zahteva odvisnosti, in tudi potomec zahteva odvisnosti. Prav tako mora prevzeti in prenesti odvisnosti starševskega razreda:
Težava se pojavi, ko želimo spremeniti konstruktor razreda BaseClass
, na primer ko dodamo novo odvisnost. Takrat
moramo spremeniti tudi vse konstruktorje otrok. Zaradi tega je takšna sprememba pekel.
Kako to preprečiti? Rešitev je, da dajete prednost sestavi pred dedovanjem**.
Zato kodo oblikujmo drugače. Izognili se bomo abstraktnim
Base*
razredom. Namesto da bi razred MyClass
pridobil določeno funkcionalnost s podedovanjem od
razreda BaseClass
, mu bo ta funkcionalnost posredovana kot odvisnost:
Vbrizgavanje množice
Odvisnosti se posredujejo s klicem metode, ki jih shrani v zasebne lastnosti. Običajno so te metode poimenovane v obliki
set*()
, zato se imenujejo setterji, seveda pa se lahko imenujejo tudi kako drugače.
Ta metoda je uporabna za neobvezne odvisnosti, ki niso potrebne za delovanje razreda, saj ni zagotovljeno, da jih bo objekt dejansko prejel (tj. da bo uporabnik poklical metodo).
Hkrati ta metoda omogoča, da se setter večkrat pokliče za spremembo odvisnosti. Če to ni zaželeno, metodi dodajte
preverjanje ali pa od različice PHP 8.1 označite lastnost $cache
z zastavico readonly
.
Klic setterja je opredeljen v konfiguraciji vsebnika DI v razdelku setup. Tudi tu se uporablja samodejno posredovanje odvisnosti s pomočjo funkcije autowiring:
Vbrizgavanje lastnosti
Odvisnosti se posredujejo neposredno lastnosti:
public
Tako nimamo nadzora nad tem, ali bo posredovana odvisnost dejansko določenega tipa (to je veljalo pred PHP
7.4), in izgubimo možnost, da bi se na novo dodeljeno odvisnost odzvali z lastno kodo, na primer da bi preprečili nadaljnje
spremembe. Hkrati lastnost postane del javnega vmesnika razreda, kar morda ni zaželeno.
Nastavitev spremenljivke je opredeljena v konfiguraciji vsebnika DI v razdelku nastavitev:
Vbrizgajte
Medtem ko so prejšnje tri metode na splošno veljavne v vseh objektno usmerjenih jezikih, je injiciranje z metodo, anotacijo ali atributom inject značilno za predstavnike Nette. Obravnavani so v ločenem poglavju.
Kateri način izbrati?
- konstruktor je primeren za obvezne odvisnosti, ki jih razred potrebuje za delovanje
- setter pa je po drugi strani primeren za neobvezne odvisnosti ali odvisnosti, ki jih je mogoče spremeniti
- javne spremenljivke niso priporočljive