Hogyan hozzunk létre saját függőségi injekciós tartályt?

  • 26.02.16 09:01 •
  • sfedosimov •
  • # 278049 •
  • Habrahabr •
  • Fordítás •
  • 0 •
  • 12300

- ugyanaz, mint Forbes, csak jobb.

Hello mindenkinek!
Ez egy ingyenes fordítás a cikk Hogyan készítsd el saját függőségi injekciós konténerét.
mert ez az első fordulata a hubra-nak, azt akarom, hogy rámutassanak a hibákra, a pontatlanságokra.

Hogyan hozzunk létre saját függőségi injekciós konténert.


A csomagológépen a "függőségi injekciós tartály" keresése jelenleg több mint 95 eredményoldalt eredményez. Magabiztosan elmondhatjuk, hogy ez a "kerék" már kitalált.

Azonban nem egy szakács arra tanult, hogy csak elkészített ételeket főzzön. Továbbá, és egyetlen fejlesztő sem tudta programozni csak a kész kódot.

Ebben a cikkben megtudhatjuk, hogyan készítsünk egyszerű függőségi injekciós tartálycsomagot. A cikken írt összes kód, valamint a 100% -os lefedettséggel rendelkező PHPDoc jegyzetek és egységvizsgálatok elérhetők a GitHubon. Mindez a csomagolóhoz is hozzá van adva.

Tervezzük a függőségi injekciós konténerünket


Kezdjük azzal, hogy megtervezzük azt, amit a konténerünk meg akar tenni.
Jó kiindulópont az, hogy a "Függőségi Injekciós tálca" két részre osztható: "Függőleges befecskendezés" és "Konténer".

A függőségi injekció elvégzésének két legáltalánosabb módja a konstruktor befecskendezés vagy szétterítő injekció. Ez egy függőségi osztály átadása egy konstruktoron argumentum vagy módszeres hívás formájában. Ha konténerünk képes lesz létrehozni egy példányt és szolgáltatásokat tartalmazni, mindkét módszert képes lesz végrehajtani.

A konténernek képesnek kell lennie a szolgáltatások példányainak tárolására és letöltésére. Ez egy meglehetősen triviális feladat a szolgáltatás létrehozásához képest, de még mindig bizonyos figyelmet igényel. A konténer-interop csomag olyan interfészeket tartalmaz, amelyeket a konténer megvalósíthat. A fő felület a ContainerInterface. amely két módszert határoz meg: az egyik a szolgáltatás fogadására, a másik pedig a szolgáltatás meghatározásának ellenőrzésére.

Tapasztalatok más függőségi injekciós tálcákról


A Symfony Dependency Injection Container lehetővé teszi számunkra, hogy különböző szolgáltatásokat határozzunk meg. A YAML-ban. a tároló konfigurációja így fog kinézni:

A PHP-ben ugyanaz a konfiguráció a Symfony Dependency Injection összetevőhöz hasonlóan fog kinézni:

Első lépések


Az első dolog, amire szükségünk van, egy könyvtárat és egy, a composer.json nevű fájlt hoz létre. amely a Zeneszerzőt használja. hogy osztályaink autoloaderja működött. Az egész fájl jelenleg a namespace-hez tartozó SitePoint \ Container térkép az src könyvtárhoz.


Továbbá, ahogy fogunk tenni, a konténerünk végrehajtja a konténer-interop interfészt. szükségünk van a zeneszerzőre, hogy feltöltsük őket, és adjunk hozzá egy fájlt a zeneszerzőhöz. json:


A ContainerInterface fő felületével együtt. A konténer-interop csomag két kiviteli felületet is definiál. Az első a általános kivételeknél a szolgáltatás létrehozásakor, a másik pedig kivételek esetén, amikor a kért szolgáltatás nem található. Másik kivételt is hozzáadunk ehhez a listához azokban a helyzetekben, amikor a kért paraméter nem található.

Mivel nem szükséges hozzáadni olyan funkciókat, amelyek meghaladják a javasolt PHP Exception rendszermag osztályt. ezek az osztályok nagyon egyszerűek. Miközben értelmetlennek tűnnek, ez a felosztás megkönnyíti számukra a külön felfogást és feldolgozást.

Hozzon létre az src mappát, és a következő src / Exception / ContainerException.php fájlokat tartalmazza. src / Exception / ServiceNotFoundException.php és az src / Exception / ParameterNotFoundException.php függvények:

Linkek a tartályban


Symfony osztály Referencia. korábban figyelembe vették, lehetővé tette a könyvtár számára, hogy megkülönböztesse az azonnali használatra szánt PHP értékeket és azokat az érveket, amelyeket ki kell cserélni a konténerben lévő egyéb szolgáltatásokkal.

Hívjuk fel ezt az ötletet, és hozzunk létre két osztályt a paraméterekhez és szolgáltatásokhoz. Mivel mindkét osztály az objektum értékeket egyszerűen az erőforrás nevével tárolja, érdemes használni az alap elvont osztályt. Így kétszer nem kell ugyanazt a kódot írni.

Hozzon létre az alábbi src / Reference / AbstractReference.php fájlokat. src / Reference / ServiceReference.php és src / Reference / ParameterReference.php, vagyis:

Konténerosztály


Ideje létrehozni a konténerünket. Kezdjük a konténerosztályunk alapsémájával, és módszereinket hozzá fogjuk járni.

Az alapötlet az, hogy két tömböt vegyünk fel konténerünk építőjében. Az első tömbnek tartalmaznia kell a szolgáltatásdefiníciókat és a második paraméterdefiníciót.

Írja be a következő kódot az src / Container.php fájlban:


Mindazt, amit itt csináltunk, a ContainerInterface felületet a konténer-interop-ről hajtottuk végre, és a definíciókat olyan későbbiekben elérhető tulajdonságokra terjesztettük be. Szintén létrehoztuk a serviceStore tulajdonságot, és inicializáltuk egy üres tömbre. Amikor a konténert felkérték, hogy hozzon létre szolgáltatásokat, tároljuk őket ebben a tömbben, hogy azok később visszaállíthatók legyenek anélkül, hogy újból létrehoznunk kell őket.

Most kezdjük el a konténer-interop-ban bejelentett módszereket írni. Kezdjük a get-val ($ név). a következő módszer hozzáadásához az osztályhoz:


Győződjön meg arról, hogy a fájl elején használja a felhasználást. A get ($ name) módszer egy egyszerű ellenőrzés a szolgáltatásdefiníció jelenlétére a konténerben. Ha nem, ott lesz a ServiceNotFoundException, amelyet korábban hoztunk létre. Ha igen, visszaadja. Létrehozza és tárolja a tárolóban, ha még nem lett létrehozva.

Bár benne vagyunk benne, létre kell hoznunk egy módszert a paraméterek lekérdezéséhez a tartályból. Az n-dimenziós asszociatív tömbön a konstruktornak szánt paraméterek elfogadásával szükségünk van arra, hogy egyetlen tömbön keresztül tisztán hozzáférjünk a tömbben található bármely elemhez. Ennek az egyszerű módja, ha a pontot határolóvá szeretné használni, így a foo.bar sor a foo kulcs bar gombjára utal a paraméterlista gyökeréről.


Most olyan módszert alkalmaztunk, amelyet még nem írtunk. Az elsőnek van ($ neve). amely konténer-interop-ban szerepel. Ez elég egyszerű módszer, és csak akkor kell ellenőrizni, ha a konstruktorhoz megadott definíciók tömbje tartalmazza a $ name szolgáltatást.


Egy másik módszer, amit meg kell írni, a createService ($ név). Ez a módszer a szolgáltatás létrehozásához használt fogalommeghatározásokat fogja használni. Mivel nem szeretnénk, ha ezt a módszert a tartályon kívülről hívják, privátnak kell lenni.

Az első dolog, amit ebben a módszerben kell elvégezni, ésszerű ellenőrzések.
Minden egyes bejelentett szolgáltatáshoz egy olyan tömbre van szükségünk, amely tartalmazza az osztálykulcsot és az opcionális argumentumokat, valamint a hívásgombokat. Ezeket fogják használni a kivitelező és a szetter implementálásához. Hozzáadhatunk védelmet a linkhurokból is, ellenőrizzük, hogy már megpróbáltunk-e létrehozni egy szolgáltatást.

Ha az argumentum argumentum létezik, azt szeretnénk, hogy az argumentum-definíciók ezen tömbjét olyan PHP-értékek tömbévé alakítsuk át, amelyet át lehet adni a konstruktornak. Ennek érdekében meg kell változtatnunk a korábban bejelentett objektumok könyvtárát a tartályban hivatkozott értékekre. Ezen a ponton ezt a logikát a resolveArguments ($ name, array $ argumentDefinitons) módszerben használjuk.
A ReflectionClass :: newInstanceArgs () módszerrel létrehozunk egy szolgáltatást az argumentum tömb használatával. Ez a kivitelező megvalósítása.

Ha a hívási kulcs létezik, szeretnénk használni a hívásdefiníciók tömbjét, és alkalmazni azt az éppen létrehozott szolgáltatásra. Ismét használni fogjuk a logikát egy külön eljárásban, amelyet initializeService ($ szolgáltatás, $ name, array $ callDefinitions) definiálunk. Ez a beállító végrehajtása.


Ez utóbbi módszer végrehajtja a beállítót a szolgáltatásobjektum egy példányában. Ehhez át kell mennie a definíciók tömbjében, amikor felhívja a módszert. A módszer kulcsot használjuk a módszer meghatározására, és az opcionális argumentumkulcs használható arra, hogy argumentumokat szolgáltasson ehhez a módszerhez. Használhatjuk azt a módszert, amelyet csak azért írtunk, hogy az érveit PHP értékekre fordítsa.


És most már van egy kész függőség befecskendező tartálya. A használati példák megtekintéséhez ellenőrizze a GitHub-ban található adattárat.

következtetés


Megtanultuk, hogyan hozzunk létre egy egyszerű függőségi injekciós tartályt. De sok olyan tároló van, amelyeknek még nincsenek kiemelkedő jellemzői.

Bizonyos függőségi befecskendező tartályok, mint például a PHP-DI és az Aura.DI egy olyan automatikus kapcsolatot jelentenek. Ez az a hely, ahol a tartály kitalálja, hogy a tárolóból milyen szolgáltatásokat kell végrehajtani másokban. Ehhez a Reflection API-t a konstruktor paramétereinek megismerésére használják.

Csak a regisztrált felhasználók vehetnek részt a felmérésben. Jelentkezzen be. kérem.

Kapcsolódó cikkek