Cel mai adesea, luăm lucrurile de la sine înțeles. Dacă ceva funcționează așa cum era de așteptat, nu ne deranjăm despre funcționarea interioară a acesteia pentru a înțelege mecanismul care stă la baza acesteia. Sau să o punem într-un alt mod, nu vom săpați în ceva până când nu avem probleme!
În mod similar, mereu mă întrebau despre câteva concepte din OpenCart care au fost folosite în cadrul de bază, iar una dintre ele a fost clasa Proxy. Mi-a luat ceva timp să înțeleg și m-am gândit că este o chestie grozavă de a împărtăși cu tine, pentru că întotdeauna este distractiv să știi ceva nou.
Deși veți găsi diverse materiale online care definesc termenul proxy, definiția din Wikipedia este frapantă și ușor de înțeles.
Un proxy, în cea mai generală formă, este o clasă care funcționează ca o interfață cu altceva.
Astfel, proxy-ul deleagă controlul obiectului pe care intenționează să-l folosească și acționează astfel în numele clasei actuale care a fost instanțiată. De fapt, modelul de design proxy este un model foarte popular care este folosit de cadrele populare după cum este necesar. Având în vedere faptul că o discuție despre metoda proxy în sine este un subiect atât de larg și în afara acestui articol, voi rezuma rapid ceea ce este folosit de cele mai multe ori:
În contextul OpenCart, am putea spune că modelul proxy este folosit pentru a adăuga funcționalitate la clasa proxy de bază. Acestea fiind spuse, clasa proxy de bază nu oferă nimic altceva decât câteva metode magice! Așa cum vom vedea în următoarea secțiune, clasa proxy este îmbogățită la timpul de execuție prin atașarea de proprietăți.
Înainte de a ne muta în secțiunea următoare, să examinăm rapid clasa proxy. Se află în Sistem / motor / proxy.php
.
$ Cheie; funcția publică __set ($ cheie, valoarea $) $ this -> $ key = valoarea $; funcția publică __call ($ key, $ args) $ arg_data = array (); $ args = func_get_args (); foreach ($ args ca $ arg) dacă ($ arg instanceof Ref) $ arg_data [] = & $ arg-> getRef (); altceva $ arg_data [] = & $ arg; dacă (isset ($ this -> $ key)) returnă call_user_func_array ($ this -> $ key, $ arg_data); altceva $ trace = debug_backtrace (); Ieșire('Înștiințare: Proprietate nedefinită: Proxy :: '. cheie cheie. "în ". $ trace [1] ['fișier']. ' pe net ". $ trace [1] ['linie']. '„);
După cum puteți vedea, ea implementează trei metode magice: __obține()
, __a stabilit()
, și __apel()
. Printre acestea, __apel()
implementarea metodei este una importantă și vom reveni la ea destul de curând.
În această secțiune, vă voi explica exact cum este un apel $ This-> model_catalog_category-> getCategory ($ category_id)
funcționează din cutie.
De fapt, povestea începe cu următoarea declarație.
$ This-> a sarcinii> Model ( 'catalog / categorie');
În timpul procesului de bootstrare, cadrul OpenCart stochează toate obiectele generice la Registru
astfel încât să poată fi extrași la voia lor. Ca urmare a acestui fapt, $ This-> încărcare
apelul returnează Încărcător
obiect al Registrului.
Încărcător
clasa oferă diferite metode pentru a încărca componente diferite, dar ceea ce ne interesează aici este model metodă. Să tragem rapid fragmentul model
metoda de la Sistem / motor / loader.php
.
model de functie publica ($ route) // Sanitiza apelului $ route = preg_replace ('/ [^ a-zA-Z0-9 _ \ /] /', ', (string) $ route) $ this-> registry-> get ('event') -> trigger ('model /'. $ route. '/ before', array (& $ route) 'model_' str_replace (array ('/', '-', '.'), array ('_', '), $ route))) $ file = DIR_APPLICATION. . '.php'; $ class = 'Model'. preg_replace ('/ [^ a-zA-Z0-9] /', '$ cale); dacă (is_file ($ file)) include_once ($ file); $ proxy = proxy nou (); foreach (metoda $ get_class_methods ($ class) ca metodă $) $ proxy -> $ method = $ this-> callback ($ this-> registry, $ route. '/'. $ this-> registry-> set ('model_'. str_replace (array ('/', '-', '.' proxy); altceva throw new \ Exception ('Eroare: nu a putut fi încărcat modelul'. $ route. '!'); // declanșează evenimentele $ this-> registry-> get ('event') -> trigger ('model /'. $ Route. '/ After', array (& $ route);
Având în vedere exemplul menționat anterior, valoarea lui $ traseu
argumentul este Catalog / categorie
. În primul rând, valoarea $ traseu
variabilă este dezinfectată, iar după aceea declanșează inainte de
pentru a permite altor ascultători de module să modifice valoarea $ traseu
variabil.
Apoi, verifică existența obiectului model solicitat în registru. Dacă Registrul deține obiectul solicitat, nu este necesară o altă prelucrare.
Dacă obiectul nu este găsit, urmează o procedură interesantă pentru ao încărca și este fragmentul pe care îl căutăm în contextul acestui articol.
Pentru început, pregătește calea fișierului modelului solicitat și îl încarcă dacă există.
... $ file = DIR_APPLICATION. 'model/' . $ rută. '.Php'; $ class = 'Model'. (fișier ($ file)) include_once ($ file); ... ... dacă este (este_file ($ file));
În consecință, instanțiază instanța împuternicire
obiect.
$ proxy = proxy nou ();
Acum, atenție la următorul pentru
buclă - face mult mai mult decât pare.
foreach (metoda $ get_class_methods ($ class) ca metodă $) $ proxy -> $ method = $ this-> callback ($ this-> registry, $ route. '/'.
În cazul nostru, valoarea lui clasa $
ar trebui să fie ModelCatalogCategory
. get_class_methods (clasa $)
fragmentul încarcă toate metodele din ModelCatalogCategory
clasa și buclele prin ea. Ce face în buclă? Să ne uităm atent.
În buclă, el cheamă suna inapoi
din aceeași clasă. Este interesant de observat că metoda de returre returnează funcția apelată care este atribuită $ proxy
obiect cu cheia ca nume de metoda. Desigur, obiectul proxy nu are astfel de proprietăți; acesta va fi creat în zbor folosind __a stabilit()
magie!
Apoi, $ proxy
obiect este adăugat la registru, astfel încât să poată fi extras mai târziu când este necesar. Priviți cu atenție componenta cheie a a stabilit
metodă. În cazul nostru, ar trebui să fie model_catalog_category
.
$ ',' - ','. '), array (' _ ',', '), (string) $ route), $ proxy );
La sfârșit, o să sune după
pentru a permite altor ascultători de module să modifice valoarea $ traseu
variabil.
Aceasta este o parte din poveste.
Hai să vedem ce se întâmplă exact când folosiți următoarele în controlerul dvs..
$ This-> model_catalog_category-> getCategory ($ category_id);
$ This-> model_catalog_category
fragmentul încearcă să găsească o potrivire pentru model_catalog_category
cheie în Registru. Dacă vă întrebați cum, doar căutați în Controlor
clasa în Sistem / motor / controller.php
fișier - acesta oferă __obține()
metode magice care o fac.
După cum tocmai am discutat, ar trebui să ne întoarcem $ proxy
obiect atribuit acelei anumite chei. Apoi, încearcă să apeleze getCategory
pe acest obiect. Dar clasa Proxy nu implementează o astfel de metodă, deci cum funcționează aceasta?
__apel()
metoda magică vine la salvare! Ori de câte ori apelați o metodă care nu există în clasă, comanda este transferată la __apel()
magie.
Să explorăm în detaliu pentru a înțelege ce se întâmplă. Deschideți fișierul de clasă proxy și acordați atenție acestei metode.
cheie $
conține numele funcției care se numește-getCategory
. Pe de altă parte, $ args
conține argumente transmise metodei și ar trebui să fie o matrice a unui element care deține id-ul categoriei care este trecut.
Apoi, există o matrice $ arg_data
care stochează referințele argumentelor. Sincer, nu sunt sigur dacă codul Exemplu $ arg Ref
are sens sau nu acolo. Dacă cineva știe de ce este acolo, aș fi fericit să învăț.
În plus, încearcă să verifice existența cheie $
proprietate în $ proxy
obiect, și rezultă în ceva de genul acesta.
dacă (isset ($ this-> getCategory))
Reamintim că mai devreme am atribuit toate metodele de ModelCatalogCategory
clasa ca proprietăți ale $ proxy
obiect utilizând a pentru
buclă. Pentru comoditatea dvs., voi reintroduce codul din nou.
... foreach (metoda get_class_methods ($ class) ca metodă $) $ proxy -> $ method = $ this-> callback ($ this-> registry, $ route. '/'. ...
Deci, ar trebui să fie acolo, și ar trebui să ne întoarcă, de asemenea, funcția apelabilă! În cele din urmă, aceasta numește funcția care poate fi apelată cu ajutorul funcției call_user_func_array
funcția prin trecerea funcției callabile în sine și a argumentelor metodei.
Acum, să ne redirecționăm atenția asupra definiției callabile a funcției în sine. Îmi iau fragmentul din suna inapoi
metoda definită în Sistem / motor / loader.php
.
... funcția ($ args) utilizează ($ registry, & $ route) static $ model = array (); $ output = null; // Activați pre evenimentele $ result = $ registry-> get ('event') -> trigger ('model /'. $ Route '/ before', array (& $ route, & $ args, & output) ); dacă ($ rezultat) return $ result; // Stocați obiectul modelului dacă (! Isset ($ model [$ route])) $ file = DIR_APPLICATION. 'model/' . substr ($ rută, 0, strrpos ($ rută, '/')). '.Php'; $ class = 'Model'. (fișier ($ file)) include_once ($) () () () fișierul) $ model [$ route] = noua clasă $ ($ registry); altceva aruncă o nouă \ Exception (' ) $ method = substr ($ route, '/') + 1); $ callable = array ($ model [$ route]; ($ callable)) $ output = call_user_func_array ($ callable, $ args); altceva arunca noua \ Exceptie ('Eroare: evenimente $ $ $ = $ registrar-> get ('event') -> trigger ('model /'. $ route. '/ after', array (& $ route, & $ args, rezultatul) return $ result; return $ output;; ...
Deoarece este o funcție anonimă, ea a păstrat valorile sub formă de $ registru
și $ traseu
variabilelor care au fost transferate mai devreme în metoda de apel invers. În acest caz, valoarea lui $ traseu
variabilă ar trebui să fie Catalog / categorie / getCategory
.
În afară de aceasta, dacă privim la fragmentul important în acea funcție, instanțiază ModelCatalogCategory
obiect și îl stochează într-o statică model de $
mulțime.
... // Stocați modelul obiect dacă (! Isset ($ model [$ route])) $ file = DIR_APPLICATION. 'model/' . substr ($ rută, 0, strrpos ($ rută, '/')). '.Php'; $ class = 'Model'. (fișier ($ file)) include_once ($) () () () fișierul) $ model [$ route] = noua clasă $ ($ registry); altceva aruncă o nouă \ Exception (' )). ')'; ...
Iată un fragment care apreciază numele metodei care trebuie apelat utilizând $ traseu
variabil.
$ method = substr ($ rută, strrpos ($ rută, '/') + 1);
Deci, avem o referință de obiect și un nume de metodă care ne permite să o numim folosind call_user_func_array
funcţie. Fragmentul următor face exact acest lucru!
... dacă (is_callable ($ callable)) $ output = call_user_func_array ($ callable, $ args); altceva aruncați o nouă \ Excepție ("Eroare: Could not call model / '. $ route.' ''); ...
La sfârșitul metodei, rezultatul rezultat este returnat prin $ ieșire
variabil. Și da, asta eo altă parte a povestirii!
Am ignorat în mod intenționat pre și post cod de evenimente care vă permite să înlocuiți metodele din clasele de bază OpenCart. Folosind acest lucru, puteți suprascrie orice metodă de clasă de bază și puteți modifica-o după necesitățile dvs. Dar să păstrăm asta pentru o altă zi, pentru că va fi prea mult pentru a se încadra într-un singur articol!
Deci așa funcționează cu totul. Sper că ar trebui să fiți mai încrezători în apelurile de stenogramă OpenCart și în ceea ce privește lucrările lor interne.
Ceea ce am discutat astăzi este unul dintre conceptele interesante și ambigue în OpenCart: utilizarea metodei Proxy într-un cadru care să sprijine convențiile de stenogramă pentru a apela metode de modelare. Sper ca articolul să fie destul de interesant și să vă îmbogățească cunoștințele despre cadrul OpenCart.
Mi-ar plăcea să știu feedback-ul dvs. cu privire la acest lucru, și dacă vă simțiți că ar trebui să acopere astfel de subiecte în articolele mele viitoare, nu ezitați să renunțe la o linie despre asta!