Dependența de injecție în PHP

Injectarea de dependență a fost un subiect frecvent de discuții între mulți dezvoltatori corporativi în ultimii ani. Mulți s-au temut că ar putea sacrifica prea mult timp construind arhitectura aplicațiilor fără a face nici o muncă reală. În acest articol, vă voi explica de ce dezvoltatorii PHP ar trebui să ia în considerare posibilitatea de a profita de injecția de dependență, atunci când construiți proiecte mari și scalabile.


Ce este injecția de dependență?

Înainte de a sapa în subiect, să definim cu exactitate ce este injecția de dependență. Să ne imaginăm că lucrați în prezent pe un site web "Întrebări și răspunsuri", similar cu "Overflow de stive". Ar fi mai mult decât probabil să creați o clasă, numită Întrebare, care ar conține un membru de tip Autor. În vremurile vechi, programatorii ar fi creat Autor obiecte direct în Întrebare constructor, astfel:

clasa autorului private $ firstName; private $ lastName; funcția publică __construct ($ firstName, $ lastName) $ this-> firstName = $ firstName; $ this-> lastName = $ lastName;  funcția publică getFirstName () return $ this-> firstName;  funcția publică getLastName () return $ this-> lastName;  clasa Întrebare privat $ author; întrebare privată $; funcția publică __construct ($ question, $ authorFirstName, $ authorLastName) $ this-> author = autor nou ($ authorFirstName, $ authorLastName); $ this-> question = $ question;  funcția publică getAuthor () return $ this-> author;  funcția publică getQuestion () return $ this-> question; 

În timp ce mulți programatori ar putea numi acest cod bun, există, de fapt, multe probleme cu acesta:

  • Informațiile autorului au fost transmise către Întrebare constructorul nu are nimic de făcut înăuntru Întrebare. Numele unui autor ar trebui să fie în interiorul Autor deoarece nu are nimic de-a face cu întrebarea în sine.
  • Autor clasa este strâns cuplată cu Întrebare clasă. Dacă adăugăm un nou parametru la Autorconstructorul, atunci trebuie să modificăm fiecare clasă unde creăm un Autor obiect - un proces obositor și lung, în special în aplicații mari.
  • Unitatea de testare a Întrebare clasa creează comportamentul nedorit de a fi nevoit să testeze Autor și clasa.

Injecția de dependență atenuează aceste probleme prin inserarea dependențelor prin constructorul clasei dependente ("Constructor Injection"). Rezultatul este un cod foarte sustenabil, care ar putea arăta astfel:

clasa autorului private $ firstName; private $ lastName; funcția publică __construct ($ firstName, $ lastName) $ this-> firstName = $ firstName; $ this-> lastName = $ lastName;  funcția publică getFirstName () return $ this-> firstName;  funcția publică getLastName () return $ this-> lastName;  clasa Întrebare privat $ author; întrebare privată $; funcția publică __construct ($ question, Autor autor $) $ this-> author = $ author; $ this-> question = $ question;  funcția publică getAuthor () return $ this-> author;  funcția publică getQuestion () return $ this-> question; 

Avantajele injecției de dependență

Trebuie să utilizați injecția de dependență pentru proiecte pe termen lung.

Am lucrat la multe proiecte comerciale în cariera mea. Unele dintre ele sunt foarte bine scrise; cu toate acestea, trebuie să spun că majoritatea dintre ele au o calitate a codurilor considerabil slabă. Recent am fost desemnat să lucrez la o astfel de bază de cod ...

O companie a solicitat cererea în 2009. Bugetul proiectului a fost planificat în mod corespunzător, dar managerul de proiect dorea ca aplicația să fie construită foarte rapid pentru a-și impresiona șeful. Cel puțin, asta mi-a spus colegul meu. Scrierea rapida a unei aplicatii ar putea suna foarte bine pentru a reduce costurile, dar inseamna, de asemenea, ca dezvoltatorii au sarit in codul fara planificare corespunzatoare.

Dezvoltatorii au scris rapid codul, creând clase necesare pentru a îndeplini funcționalitatea necesară. Caracteristicile s-au modificat pe măsură ce proiectul a evoluat și, deoarece proiectul a fost prost planificat (și fiecare clasă a fost strâns cuplată), proiectul a devenit dificil de dezvoltat.

În prezent, este dificil să lucrezi la acest proiect. Modificarea unei clase simple duce la o cascadă de alte modificări în alte clase, deoarece totul este cuplat împreună - ducând la multe bug-uri. De fiecare dată când ceva este modificat, dezvoltatorul trebuie să urmărească și să repare bug-uri.

Aplicația este, de asemenea, imposibilă să se testeze unitatea, degradând calitatea codului.

Fiecare caracteristică trebuie testată manual, pierzând timp prețios care ar putea fi petrecut în altă parte. De fapt, pentru a reduce costul testelor manuale, am creat software pentru a testa infrastructura aplicației. Da, a trebuit să creăm un nou software pentru a testa produsul real.

Compania a aflat că încercarea de a scrie rapid software a dus la costuri neașteptate. La început, compania a făcut o mulțime de bani, deoarece le-a plătit foarte mult, dar după trei ani, au pierdut bani pe această cerere. Suma de bani pe care au tras-o nu acoperă cheltuielile continue și mari de întreținere. Ei au pierdut, de asemenea, mulți dezvoltatori buni, care au pierdut dorința de a lucra la proiect.

Dacă aplicația folosește injecția de dependență, dezvoltatorii ar fi fost capabili să testeze în mod corespunzător aplicația completă, ducând la costuri reduse de întreținere și depanare. Compania s-ar fi concentrat pe crearea de noi caracteristici care durează, în loc să piardă calitatea software-ului de fiecare dată când a fost introdusă o nouă caracteristică. De asemenea, i-ar fi păstrat pe membrii echipei de vârf și ar fi evitat să-și piardă banii prin găsirea și angajarea de noi angajați (ceea ce este dificil de început în orașul meu).


Noțiuni de bază cu privire la un buget limitat

În timp ce injecția de dependență vă ajută să vă asistați în scrierea unui cod mai bun, aceasta poate necesita și timp și efort suplimentar pentru ao face corect. Acest lucru se poate dovedi a fi o problemă, dacă aveți nevoie de un cod de lucru pentru o demonstrație.

Dacă tot ce aveți nevoie este o dovadă a conceptului, atunci vă sugerez să nu pierdeți timpul cu injecție de dependență și arhitectură adecvată.

Salt în dreapta și începe codarea. Puteți face lucrurile în mod corect după aprobarea proiectului și aveți finanțarea necesară. De fapt, odată ce ai o finanțare adecvată, aruncă demo-ul tău și începe de la zero. În caz contrar, cererea dvs. va sfârși ca un spaghetti-cod-gun-can.


Cod de pornire confortabil

Deci, ați început să vă deplasați dependențele de la constructorii dvs. de clasă, dar pe măsură ce proiectul crește, veți ajunge la multe niveluri de obiecte care trebuie create atunci când începe aplicația. În funcție de mărimea aplicației dvs., crearea tuturor obiectelor pentru lansarea aplicației poate fi un proces foarte lung și poate afecta performanța aplicației dvs. (precum și rezultatul unui cod dezordonat). Iată un exemplu:

/ * Rețineți că natura aplicației nu este importantă aici. Am vrut doar să arăt cât de greu poate fi un astfel de cod: * / $ filePath = "/ path / to / file"; $ fileBuilderFactory = nou ConcreteFileBuilderFactory (); $ filesXmlBuilderFactory = noul ConcreteFilesXmlBuilderFactory ($ fileBuilderFactory); $ softwaresRetrieverCriteriaBuilderFactory = nou ConcreteSoftwaresRetrieverCriteriaBuilderFactory ($ filesXmlBuilderFactory); $ softwareRetrieverCriteriaBuilderFactory = nou ConcreteSoftwaresSoftwareRetrieverCriteriaBuilderFactory ($ filesXmlBuilderFactory); $ fișiereJsonBuilderFactory = noul ConcreteFilesJsonBuilderFactory ($ fileBuilderFactory); $ objectBuildderFactory = nou ConcreteSoftwaresSoftwareObjectBuilderFactory (); $ softwareSoftwareBuilderFactory = noul ConcreteSoftwaresSoftwareBuilderFactory ($ objectBuildderFactory); $ xmlSoftwareRepository = noul XmlSoftwareRepository ($ softwaresSoftwareBuilderFactory); $ softwaresBuilderFactory = noul ConcreteSoftwaresBuilderFactory ($ xmlSoftwareRepository, $ softwareRetrieverCriteriaBuilderFactory, $ filesJsonBuilderFactory); $ xmlSoftwaresRepository = noul XmlSoftwaresRepository ($ softwaresBuilderFactory); $ softwareToHashMap = nou ConcreteSoftwareToHashMap (); $ softwaresToHashMap = nou ConcreteSoftwaresToHashMap ($ softwareToHashMap); $ jsonSoftwaresService = noul JsonSoftwaresService ($ softwaresToHashMap); $ di = noua dependență de injectare ($ softwaresRetrieverCriteriaBuilderFactory, $ xmlSoftwaresRepository, $ jsonSoftwaresService);

Acest cod de pornire este destul de mic. Dacă construiți o aplicație mare, codul dvs. de pornire poate deveni mult mai greu decât acesta. Inutil să spun, acest lucru duce la unele dificil de a menține codul.

Pentru a rezolva această problemă, avem nevoie de o aplicație de injecție de dependență care citește un fișier XML și creează toate obiectele necesare pentru lansarea aplicației. Obiectele vor fi apoi serializate și scrise într-un fișier. Codul de pornire va citi apoi acel fișier și va crea direct obiectele. Acest lucru face ca codul dvs. de pornire să fie la fel de simplu:

 $ objectFilePath = "/ cale / spre / serializate / obiect / fișier"; $ di = neserializează (file_get_contents ($ objectFilePath));

Software pentru injectarea dependenței de sursă deschisă

Cele mai multe companii nu au prea multă bugetare pentru a crea instrumente, cum ar fi un cadru de injectare a dependenței. Cu toate acestea, puteți găsi multe soluții gratuite și open source pe web. Symfony2 folosește o componentă DI foarte solidă bazată pe Java Spring. Cu toate acestea, voi acoperi programarea unei soluții de injectare a dependenței în viitorul apropiat, dacă vă interesează. Rămâneți aproape!


PHP Devs și dependența de injecție

Nu vreau să generalizez, dar, datorită popularității sale, mulți dezvoltatori PHP sunt pasionați, care iubesc să amestece PHP și HTML.

În mod normal, acești dezvoltatori nu își planifică proiectul; ei vor doar să scrie rapid codul pentru a "face lucruri terminate".

Cred că angajarea acestor tipuri de dezvoltatori este cel mai rău lucru pe care un manager îl poate face. Subliniind importanța injecției de dependență, puteți face acești "hackeri" dezinteresați în compania dvs., în timp ce, în același timp, atrageți dezvoltatorii buni să lucreze pentru compania dvs. Cu alte cuvinte, proiectul dvs. va atrage dezvoltatori avansați, ceea ce reprezintă cea mai importantă resursă pe care ar putea-o achiziționa o companie de dezvoltare software!


Când să utilizați injecția de dependență

Injecția de dependență este cea mai utilă atunci când lucrați pe proiecte pe termen lung.

Din experiențele mele, injecția de dependență este cea mai utilă atunci când lucrați pe proiecte pe termen lung - proiecte care sunt dezvoltate și menținute activ pe o perioadă lungă de timp. Acest lucru reduce foarte mult costurile dvs. și atrage cei mai buni dezvoltatori. Dar, așa cum am menționat mai devreme, dacă aveți nevoie de o aplicație demo pentru a obține un contract sau o finanțare, aș recomanda saparea direct în cod. Dacă urmați această cale, însă, fiți conștienți de faptul că demo-ul va trebui să fie aruncat după ce achiziționați contractul și / sau finanțarea.


Timpul pentru o poveste!

Îmi plac povestile despre dezvoltatorii care doresc să facă ceea ce trebuie, dar colegii lor doresc să renunțe la cele mai bune practici și să împingă un proiect cât mai repede posibil. Care sunt gandurile tale privind injectia de dependenta? O supra-complicație sau o cerință pentru orice aplicație durabilă?

Cod