Sintaxă și funcționalitate. Separă HTML și PHP

Și toți ceilalți ca ei, motivul este că mi se pare că motorul de șabloane ar trebui să scape de utilizarea logicii în șabloane și să nu-și impună propria sintaxă pentru aceeași logică.
Cu alte cuvinte, așa: , sau așa

  1. ( pentru fiecare nume = my from = array ("Unul", "Doi", "Trei") cheie = "i" element = "text" )
abordările sunt absolut inacceptabile pentru mine!
Poate că, dintre toate motoarele de șabloane, xtemplate îmi satisface cel mai mult cerințele, dar a făcut-o o serie intreaga neajunsuri care mă irită, de exemplu, faptul că toate paginile trebuie încadrate în blocuri, sau faptul că interpretează șabloane și nu compilează, deci nu se poate lăuda cu viteză. Ei bine, ultimul lucru - am decis să scriu un motor de șabloane în așa fel încât să nu existe probleme cu adăugarea de funcționalități și, de asemenea, să fie compatibil cu motorul de șabloane nativ cu care am folosit înainte și cu care eram obișnuit. Ideea este că designul
  1. $tpl -> assigned_var = "abc" ;
pe care motoarele de șabloane native le folosesc adesea, îmi place mult mai mult decât ceva de genul:
  1. $thl -> atribui ("assigned_var" , "abc" );
La un moment dat mi-am dat seama că era mai ușor să-mi scriu propriul motor de șabloane decât să caut unul care să mi se potrivească. Și cred că am avut dreptate, pentru că a durat câteva seri.
În general, mi s-a părut că procesul este destul de interesant și au fost multe puncte pe care aș dori să le discut cu comunitatea.

Voi începe cu o descriere a sintaxei:

1) Variabile:

Totul este ca de obicei aici, cu excepția faptului că nu există „($”
Logica de afaceri Eşantion
  1. $tpl -> var_name = "..." ;
  1. (nume_var)
  1. $tpl -> var_name [ "sub_var" ] = "..." ;
  1. (var_name.sub_var)

2) Blocuri:

Sunt necesare pentru a scăpa de construcții precum (foreach name=my from=array ("Unul","Doi","Trei") key="i" item="text")
La fel ca xtpl, dar este doar ușor automatizat, și anume, pentru a analiza un bloc (se spune și replica), trebuie doar să transmiteți o serie de date șablonului!
Logica de afaceri Eşantion
  1. $tpl -> block_name [ "num" ] = "4" ;
  2. $tpl -> block_name [ "num" ] = "8" ;
  3. $tpl -> block_name [ "num" ] = "15" ;
  1. (nume_bloc.num)
  1. $tpl -> cuvinte [ "bloc" ] = matrice (
  2. O => array("cuvânt" => "A" ),
  3. 1 => matrice("cuvânt" => "B" ),
  4. 2 => matrice("cuvânt" => "C" ),
  1. (cuvinte.bloc.cuvânt)
Pentru a afișa o variabilă bloc în interior, trebuie să o denumiți (nume_bloc.nume_variabilă)
Acest lucru vă permite să accesați atât variabilele bloc, cât și variabilele externe din interior
Un bloc poate fi absolut orice variabilă, de exemplu, în al doilea exemplu, blocul este construit folosind elementul „bloc” al matricei „cuvinte”
Un bloc poate fi, de asemenea, în interiorul altui bloc, de exemplu, iată o modalitate simplă de a construi o masă de înmulțire:
Logica de afaceri Eşantion
  1. pentru ($i = 1; $i< 10 ; $i ++ )
  2. pentru ($j = 1; $j< 10 ; $j ++ )
  3. $tpl ->
  1. (table.row.num)

3) Verificări:

În esență, un tip de bloc. Este necesar fie pentru a arăta ce este înăuntru sau nu, pe baza unei variabile. Va deveni mai clar cu un exemplu:
Logica de afaceri Eşantion
  1. $tpl -> f_text = true ;
  1. Atâta timp cât f_text==true vom vedea acest text
  1. $tpl -> f_text = false ;
  1. Puteți scrie orice doriți aici, pentru că clientul nu îl va vedea.

4) Funcții:

Aceasta este mai degrabă o caracteristică experimentală, aș dori să aud o opinie dacă această abordare are dreptul la viață: Vă rugăm să rețineți că funcțiile ar trebui adăugate în mod specific la clasa de motor de șablon.
Pe în acest moment funcțiile funcționează cu un singur parametru și mă gândesc cum să extind numărul de parametri - așa: , sau așa: sau altceva. Deocamdată înclin spre prima opțiune, este mai ușor de implementat!

Acum despre principii:

Am decis să împart motorul de șablon în două părți:

1) Motorul de șablon în sine (cât mai compact posibil, tot ce aveți nevoie)
2) Compiler (și aici este totul)
Acest lucru este necesar pentru a îmbunătăți performanța, deoarece nu are rost în 8 KB de cod de compilator dacă șablonul a fost deja compilat și nu s-a schimbat de atunci.

Procesul de includere în șabloane m-a făcut să mă gândesc mult:

La prima vedere, momentul poate părea banal, dar nu este. În general, incluziunile trebuiau împărțite în două părți - statice și dinamice. O includere statică este o includere obișnuită, de exemplu, o astfel de includere va fi procesată după cum urmează - codul de la some_page.html va fi inserat în locul său, timpul de modificare a fișierului șablon compilat va fi cu 1 secundă mai lung decât cel al fișierului șablon. șablonul în sine, iar din acesta motorul de șabloane va ști că trebuie să includă unul special, de asemenea, un fișier creat de compilator, la care se va adăuga următoarea linie:
  1. if (filemtime ("./some_page.html" ) != 1237369507 ) $needCompile = true ;
Astfel, atunci când acest fișier este modificat, întreg șablonul va fi recompilat.
De ce este necesar acest lucru, de ce nu introduceți pur și simplu o includere? Ce se întâmplă dacă trebuie să afișați un bloc de 1000 de linii, în interiorul căruia va fi introdusă o includere pentru comoditate? Atunci o astfel de concentrare va ajuta foarte mult productivitatea!
Acum despre un alt tip de incluziuni - dinamice. Acest miracol arată așa în motorul meu de șabloane, de exemplu: Adică nu includem un fișier pre-specificat, ci luăm numele sau o parte din nume dintr-o variabilă! Uneori poate fi foarte convenabil, dar mod vechi cu această abordare nu va mai funcționa, deoarece atunci când o variabilă este modificată în logica afacerii, trebuie inclus un alt fișier, astfel încât această construcție va fi compilată în următorul cod:
  1. randare ("" . $this -> page_name . ".html" ) ; ?>
Observ că în acest moment o astfel de includere nu va funcționa în interiorul unui bloc, adică va funcționa, dar în interiorul fișierului conectat variabilele de bloc nu vor fi disponibile, dar cred că acest lucru nu este foarte înfricoșător, pentru că, spre deosebire de xtpl, eu nevoie doar de blocuri pentru ieșirea ciclică de un fel de matrice.

Cod PHP în interior:

Îl poți folosi în siguranță și te-ai gândit bine, dar ai decis să nu îl interzici cod phpîn șabloane.
Înțeleg că va stârni multe controverse, dar cred că nu are rost să interzicem php, deoarece nu am întâlnit situații în care să aibă sens și să nu creeze inconveniente în unele situații.

Și, în sfârșit, ce principii m-au ghidat atunci când am decis care ar fi sintaxa:

1) Logica minimă, toată logica este logica de afaceri
2) Totul este cât se poate de natural
3) Mai puțin cod
4) Posibilitati maxime

Codul șablonului în sine:

  1. clasa tpl(
  2. funcția tpl($tplDir , $tmpDir ) (
  3. $this -> tplDir = $tplDir ;
  4. $this -> tmpDir = $tmpDir ;
  5. funcția Render($Path ) (
  6. $tmpName = "tpl_" . str_inlocuire(matrice("/" , " \\ " ), "." , $Path ) . „.php”;
  7. $tmpPath = $this -> tmpDir . „/” . $tmpName ;
  8. dacă (fișier_există($tmpPath))
  9. $tmpChange = timp de fișier ($tmpPath) ;
  10. $tplChange = timp de fișier ($Cale) ;
  11. if ($tplChange + 1 == $tmpChange) include ($tmpPath . ".coll.php" ) ;
  12. elseif ($tplChange != $tmpChange) $needCompile = true;
  13. dacă ($needCompile) (
  14. # Apelul compilatorului
  15. include_once "tcompiler.class.php";
  16. $compiler = new tcompiler($this , $this -> tmpDir ) ;
  17. $compiler -> compilare ($this -> tplDir . "/" . $Path , $tmpPath ) ;
  18. include $tmpPath ;

După cum puteți vedea, nu este groasă, dar este rapidă!
La prima vedere, poate părea că o astfel de corectare automată:
  1. $tplName = "tpl_" . str_replace (matrice ("/" , "\\") , "." , $cale ) . „.php”;
Durează destul de mult timp să funcționeze și este mai bine să folosești un hash, dar am testat hash-ul durează mai mult.

Comparație cod:

Am decis să ofer liste de cod într-o formă convenabilă în diferite motoare de șabloane care fac același lucru, astfel încât să pot compara rapid lizibilitatea și comoditatea abordărilor
Mele
  1. $tpl -> num = 4815162342 ;
  2. $tpl -> post [ "pagina" ] [ "id" ] = 316 ;
  3. pentru ($i = 1; $i< 30 ; $i ++ ) $tpl ->bin = matrice ("dec" => $i , "bin" => decbin($i ) ) ;
  4. pentru ($i = 1; $i< 10 ; $i ++ ) for ($j = 1 ; $j < 10 ; $j ++ ) $tpl ->tabel [ $i ] [ "rând" ] [ $j ] [ "num" ] = $i * $j ;
Smarty/Quicky
  1. $smarty ->
  2. $smarty -> atribui ("post" , matrice ("pagina" => matrice ("id" => 316 ) ) );
  3. pentru ($i = 1; $i< 30 ; $i ++ ) $bin = array ("dec" =>$i , "bin" => decbin($i ) ) ;
  4. $smarty -> atribui ("bin" , $bin ) ;
  5. pentru ($i = 1; $i< 10 ; $i ++ ) for ($j = 1 ; $j < 10 ; $j ++ ) $table [ $i ] [ "row" ] [ $j ] [ "num" ] = $i * $j ;
  6. $smarty -> atribui ("tabelul" , $tabelul );
Xtemplate
  1. $xtpl -> atribui ("num" , 4815162342 );
  2. $post [ "pagina" ] [ "id" ] = 316 ;
  3. $xtpl -> atribui ("post" , $post ) ;
  4. pentru ($i = 1; $i< 30 ; $i ++ ) $xtpl ->insert_loop ("page.bin" , array ("dec" => $i , "bin" => decbin($i ) ) );
  5. pentru ($i = 1; $i< 10 ; $i ++ ) {
  6. pentru ($j = 1; $j< 10 ; $j ++ ) $xtpl ->insert_loop ("page.table.row" , "rownum" , $i * $j ) ;
  7. $xtpl -> parse ("page.table" );

Conexiune:

Motorul de șablon este conectat după cum urmează:
  1. cere_o dată „motorul_cale_la_șabloane/tpl.class.php”;
  2. $tpl = tpl nou( „calea_la_dosarului_cu_șabloane”, „calea_la_dosarul_cu_cache”) ;
Nu uitați să acordați permisiuni folderului cache!

Descărcați:

În timp ce motorul de șablon este aici pentru descărcare, deocamdată este doar Beta-versiune, deci nu ar trebui să-l testați pe proiecte serioase, am vrut doar să ascult comentarii și idei pe această temă!
Dacă experimentul are succes și cineva are nevoie de un astfel de hibrid de un motor de șablon nativ și obișnuit, cu siguranță îl voi dezvolta. Apropo, cel mai probabil se va numi „LL”.
În ceea ce privește erorile, vă rugăm să vă dezabonați la oleg<собака>emby.ru

Concluzie:

În concluzie, nu voi face afirmații puternice precum „În unele cazuri, acest motor de șablon este mai rapid decât nativ PHP”. Înțelegem cu toții că, în unele cazuri, tractorul Belarus se poate dovedi a fi mai rapid decât un Porshe Panamera nou-nouț, în orice caz, motorul șablonului va fi mai lent, fie și doar pentru că trebuie să compare datele de modificare ale șablonului și versiunea sa compilată. , iar acestea sunt două apeluri suplimentare către FS. În ceea ce privește optimizările, nimeni nu vă împiedică să optimizați codul nativ.
Desigur, ca toate motoarele de șablon, al meu funcționează mai lent decât PHP nativ, dar doar puțin, iată rezultatele testului ca dovadă:

Am efectuat toate testele de mai multe ori pentru a mă asigura că OZN nu a afectat rezultatele. Dacă ceva, le-am postat aici.

Etichete:

  • motor de șablon
  • inteligent
  • repede
  • motor de șablon
Adăugați etichete
La urma urmei, dacă stelele se aprind -
Asta înseamnă că cineva are nevoie de asta?
Vladimir Maiakovski

Introducere

În ciuda faptului că PHP în sine este deja un motor de șabloane într-o oarecare măsură, există destul de multe alte motoare de șabloane care au apărut cu un motiv. În acest articol voi compara motoarele de șabloane populare în PHP.

De ce avem nevoie de motoare de șablon?

Cu cât aplicația este mai complexă, cu atât este mai importantă separarea logicii și a prezentării. Doar prin separarea cu succes a logicii de prezentare, dezvoltatorii backend vor putea colabora eficient cu dezvoltatorii frontend. Datorită motoarelor de șabloane, dezvoltatorii de front-end (sau, în limbajul obișnuit, designerii de layout) pot schimba aspectul unei aplicații web folosind sintaxa ușor de înțeles a motorului de șabloane selectat. De obicei, șabloanele sunt bucăți mici de cod HTML care conțin rezultatul variabilelor pregătite de dezvoltatorul backend.

($menutitle)

Uneori, front-end-ul este scris în JavaScript, iar comunicarea cu back-end-ul are loc prin intermediul unui API, dar aceasta este o poveste complet diferită.

Lista de motoare de șablon pentru comparație

Următoarele criterii au fost aplicate motoarele de șabloane: acestea trebuie să fie scrise în PHP, întreținute în mod activ și acceptate de comunitatea PHP.

Lamă

Acest motor de șablon este folosit în Laravel, un framework PHP care și-a început viața în 2011 și a devenit unul dintre cadrele PHP populare. Motivul vitezei lui Blade se zvonește a fi lista mică de expresii regulate de înlocuit.

Bună ziua ((nume)) Tocmai ați câștigat ((valoare)) dolari! ((#in_ca)) Ei bine, ((taxed_value)) dolari, după taxe. ((/in_ca))

inteligent

Smarty a apărut la începutul anilor 2000, încă se dezvoltă și concurează cu proiecte mai tinere.

(( foo )) (# comentariu #) (% if foo %)(% endif %)

Volt

Volt este folosit în cadrul Phalcon (un cadru scris în C și distribuit ca extensie PHP). Singurul dezavantaj pe care îl putem remarca este că Volt poate fi folosit doar în Phalcon, adică nu este posibil să îl utilizați într-un proiect pe alt cadru.

Abonați Stele Furci
752 9 460 1 734
(# app/views/products/show.volt #) (% bloc last_products %) (% pentru produs în produse %) * Nume: (( product.name|e )) (% dacă product.status === „Activ " %) Preț: (( product.price + product.taxes/100 )) (% endif %) (% endfor %) (% endblock %)

Cum să alegi un motor de șablon?

Atunci când alegeți un motor de șablon, trebuie să luați în considerare următorii factori: sintaxă, logică, extensibilitate, documentație, activitate de dezvoltare, suport comunității și performanță.

Lamă

Sintaxă și funcționalitate

Blade acceptă moștenirea șablonului, secțiunile, introducerea securizată de conținut și sintaxă simplă. Blade permite utilizarea PHP în interiorul șabloanelor.

Documentare si suport

Blade este bine documentat, dar documentația este de natura recenziilor, în timp ce informații mai detaliate sunt conținute în resurse terțe.

Performanţă

În timpul testului, viteza a atins 100.000 de modele pe secundă. Dar dacă luăm în considerare procesarea șabloanelor împreună cu încărcarea cadrului, atunci viteza este de aproximativ 2.200 de șabloane pe secundă.

Mustață

Sintaxă și funcționalitate

Șabloanele de mustață nu pot conține logică, așa că dezvoltatorii backend trebuie să implementeze o logică inutilă legată de prezentare.

Documentare si suport

Datorită capacităților limitate ale lui Mustache, nu este necesară o documentație extinsă și detaliată.

Performanţă

Mustața, din motive evidente, s-a dovedit a fi foarte rapidă (6.000 de modele pe secundă).

inteligent

Sintaxă și funcționalitate

Sintaxa este concisă și ușor de înțeles. Funcționalitatea este mare și extensibilă.

Documentare si suport

Documentația lui Smarty este bine organizată. Site-ul pare puțin învechit, dar asta este o problemă.

Performanţă

Smarty procesează destul de rapid șabloanele care nu sunt stocate în cache (9.634 șabloane pe secundă) și chiar mai rapid - șabloanele stocate în cache (57.115 șabloane pe secundă).

Crenguţă

Sintaxă și funcționalitate

Twig vine cu un set complet de funcții, filtre, teste și macrocomenzi extensibile.

Documentare si suport

Documentația este bine organizată, informativă și oferă informații vizuale. Comunitatea din jurul Twig este mare, cu dezvoltare activă pe GitHub. Twig este folosit în Drupal 8, al doilea cel mai popular CMS.

Performanţă

Procesarea șabloanelor care nu sunt stocate în cache are loc cu o viteză de 4.318 șabloane pe secundă, iar cele stocate în cache - 5.982.

Volt

Sintaxă și funcționalitate

Voltul este foarte asemănător cu Twig. Oferă funcționalitate pentru crearea propriilor filtre, macrocomenzi și extensii de motor.

Documentare si suport

Documentația este curată, informativă și clară. Dezvoltarea lui Volt, ca și Phalcon, este în plină desfășurare pe GitHub.

Performanţă

Datorită faptului că framework-ul este scris în C, Volt procesează 23.900 de șabloane pe secundă și de două ori mai mult atunci când este activată memoria cache.

Concluzii

Cea mai bună opțiune este Twig. Pentru că motorul de șablon nu depinde de cadru, se lansează foarte repede, conține suficientă funcționalitate, are o documentație excelentă și este în curs de dezvoltare.

Ca bonus, observ că sintaxa este identică cu Volt.

Acest articol este destinat celor care nu sunt sceptici în a scrie ceea ce s-a scris deja, în general, este pentru entuziaști, ceea ce și eu sunt;

Să începem prin a defini ce va putea face motorul nostru de șabloane:

  • selectarea din șablon în blocuri
  • procesare bloc
  • substituție variabilă

Blocuri.

Blocurile pot fi „ciclice” sau „non-ciclice”. Primul grup include blocuri, atunci când este analizat, motorul de șablon va executa o buclă cu anumiți parametri și va introduce „interiorul” blocului în pagina rezultată de mai multe ori. Vom avea nevoie de ele în vrac pentru publicarea datelor (de exemplu, o listă de titluri de știri). A doua categorie include construcții condiționate (de multe ori nu te poți descurca fără ele).

Vom stoca numele blocurilor într-o matrice:

$Blocks=matrice (array(„etichetă de deschidere”, „etichetă de închidere”, semn de bloc ciclic));

Pentru a fi mai clar, să ne uităm la un exemplu.

există un tabel de știri:

Creați știri în tabel (id int(10) unsigned NOT NULL auto_increment, title varchar(128), body text, data date, primary key (id));

trebuie să creați un șablon pentru afișarea acestei știri și un script PHP care procesează acest șablon.

Să fim de acord - vom include etichete bloc și variabile în comentariile HTML:

blocați conținutul

acum funcția de a aloca un bloc sau o variabilă:

Funcția ParseTmpl($Block) ( global $Blocks; global $Vars; // Se caută blocuri $Pos=0; while (($Pos=strpos($Block,""; dacă ($EndIndex=strpos($Block,$BlockEnd,$Pos)) ( $EndIndex+=strlen($BlockEnd); $SubBlock=substr($Block,$Pos,$EndIndex-$Pos); $Block= substr($Block,0,$Pos).Block($SubBlock,$BlockId) substr($Block,$EndIndex) ) else ($Pos=strpos($Block,"-->",$Pos) ; ) ) //Selectați variabile pentru ($i=0; $i ",$BeginIndex)) ( $Sub=substr($Block,$BeginIndex,$EndIndex-$BeginIndex+3); $Block=substr($Block,0,$BeginIndex). Variabilă($Sub,$i). substr($Block,$EndIndex+3 ) ) return $Block;

Ca argument, i se trece un șablon sau un fragment din acesta (de ce un fragment? Pentru că poate exista un alt bloc în interiorul blocului, adică „interiorul” blocului trebuie procesat separat). Apoi, caută aparițiile șirului",$Offset); if (($Offset+4)!=$EndInd) ( $S=substr($Block,$Offset+4,$EndInd-($Offset+4)); $Bl=explode(" ",$S); $BlockName=$Bl; pentru ($i=0; $i

Luați în considerare funcția Block($Block, $BlockId):

Bloc funcțional($Block, $BlockId) ( global $Blocks; $Ret=""; // Obțineți parametrii $BeginStr=$Blocks[$BlockId]; $BeginLength=4+strlen($BeginStr); $EndOperatorPos=strpos( $Block,"-->"); $Operator=substr($Block,$BeginLength,$EndOperatorPos-$BeginLength(" ",trim($Operator));"); $SubBlock=substr($Block,$EndOperatorPos+3,$EndBlockPos-$EndOperatorPos-3); dacă ($Blocks[$BlockId]) // blocul nu este ciclic (dacă ($BeginStr($Args)) ( $Ret.=ParseTmpl($SubBlock); ) ) else ( în timp ce ($BeginStr($Args)) ( $Ret.=ParseTmpl($SubBlock); ) ) returnează $Ret;

I se dă un fragment șablon care conține blocul în cauză și indexul blocului în matricea $Blocks. Pentru început, analizăm eticheta de deschidere în ea pentru parametri (acest lucru este pentru orice eventualitate, ce se întâmplă dacă trebuie să afișați nu toate știrile, ci o anumită cantitate). Adică, dacă blocul de știri începe cu linia:

Unde 5 este numărul de știri afișate.

Trebuie să putem evidenția exact o anumită cantitate de știri. Apoi, „interiorul” blocului este alocat variabilei $SubBlock pentru o analiză ulterioară. În continuare, în funcție de rezultatele verificării ciclicității blocului, numim funcția ParseTmpl, deja familiară nouă, fie când condiția este îndeplinită, fie într-o buclă până când condiția nu este îndeplinită. Condiția este un rezultat diferit de zero din executarea unei funcții cu același nume ca și blocul.

Pentru fiecare bloc ciclic, este necesar să se creeze o funcție care să returneze 0 sau nu 0, în funcție de dacă blocul trebuie analizat din nou. Aceasta ar putea fi o funcție care, la fiecare apel, va selecta următoarea bucată de date din tabelul de știri și va returna 1 dacă, de exemplu, numărul de știri selectate nu este mai mare decât suma transmisă acesteia ca unul dintre elementele matricea de argumente bloc.

Variabile.

Vom stoca variabilele într-o matrice

$Vars=array(„nume variabilă”);

La fel ca și în cazul blocurilor, vom crea funcții cu același nume care ar returna valorile acestor variabile (luați-le, de exemplu, din baza de date). Iată o secțiune a funcției ParseTmpl care extrage variabilele din șablon și le înlocuiește valorile:

Pentru ($i=0; $i ",$BeginIndex)) ( $Sub=substr($Block,$BeginIndex,$EndIndex-$BeginIndex+3); $Block=substr($Block,0,$BeginIndex). Variabilă($Sub,$i). substr($Block,$EndIndex+3);

Și funcția variabilă:

Variabilă funcție($Block, $VarId) ( global $Vars; $Ret=""; // Obțineți parametrii $BeginStr=$Vars[$VarId]; $BeginLength=4+strlen($BeginStr); $EndOperatorPos=strpos( $Block,"-->"); $Operator=substr($BeginLength,$EndOperatorPos-$Args=explode(" ",trim($Operator));

Este similar cu funcția Block, dar mult mai simplu.

Exemplu de model și funcție de blocuri și variabile.

Șablonul nostru de ieșire de știri:

[]

Și iată codul pentru lucrul cu blocuri și variabile:

$QueryResult_News=0; $QueryRow_News=0; funcția știri($Args) // Bloc știri ( global $QueryResult_News; global $QueryRow_News; $Active=$Args; if ($QueryResult_News==0) ​​​​( $QueryResult_News=mysql_query("selectați * din știri după limita de desc.) $Active "); ) if ($QueryRow_News=mysql_fetch_array($QueryResult_News)) ( return 1; ) else ( $QueryResult_News=0; return 0; ) ) function data($Args) // variabila data ( global $QueryRow_News; (isset ($QueryRow_News["data"])) ( return implode(".",array_reverse(explode("-",$QueryRow_News["data"],3))); ) else ( return ""; ) ) function ntitle ($Args) // variabila ntitle ( global $QueryRow_News; if (isset($QueryRow_News["titlu"])) ( return $QueryRow_News["titlu"]; ) else ( return ""; ) ) function nbody( $Args ) // variabila nbody ( global $QueryRow_News; if (isset($QueryRow_News["body"])) ( returnează $QueryRow_News["body"]; ) else ( return ""; ) )

$Blocks și $Vars tablouri:

$Blocks=array(array("știri","știri",0)) $Vars=array("data","ntitle","nbody");

Ei bine, asta e, motorul simplu de șabloane este gata, am făcut tot ce mi-am dorit, acum depinde de tine să-l modernizezi și să-l îmbunătățești până când îți satisface toate așteptările :)

Succes, sincer al tău elrevin.

Articolul este vechi, dar cred că este încă relevant

Am auzit prea des în ultima vreme cuvântul „motor de șablon”. Disputele între susținătorii diferitelor motoare de șablon continuă. Unii spun că logica din șabloane este bună, alții cred că este rea. Chiar și acum, foarte des există proiecte scrise fără utilizarea vreunui motor de șablon. Dar în acest articol nu voi încerca să iau parte. Nu vă voi demonstra avantajele niciunei dintre abordări. Voi încerca doar să vorbesc despre toate din punct de vedere teoretic. Acest articol nu este despre produse software specifice, ci despre modalități de a evidenția logica prezentării în aplicațiile dvs.

Termeni

Acest articol folosește o serie de termeni care s-ar putea să vă fie nefamiliari. Voi încerca să definesc câteva dintre ele.

Prezentare – logica aplicației responsabilă de afișarea datelor. Pentru aplicațiile WEB, aceasta este logica care generează pagina HTML.
Domeniu – partea din aplicație responsabilă cu prelucrarea datelor, adică care conține logica de afaceri a aplicației. Expresiile „logica de afaceri” și „logica domeniului” sunt în esență sinonime.
Șablon – Un fișier care conține HTML și niște markeri care permite procesarea acestui șablon și generarea codului HTML final pe baza acestuia.
Un motor de șablon este o aplicație care procesează un șablon.
Model, soluție standard – soluție la problemele întâlnite frecvent.

Motorul de șablon ca mit

Acesta este doar un termen care descrie o clasă de programe care înlocuiesc secvențele de șiruri cu unele date. Mai mult, este un termen de argou. În realitate, totul este mult mai complicat și necesită o înțelegere profundă și atentă a domeniului subiectului. Vom reveni la asta mai târziu, dar deocamdată să ne uităm la esența problemei.

Faptul este că cuvântul „motor de șabloane” este adesea considerat sinonim cu cuvântul „prezentare”. În lipsă, se crede că, dacă utilizați un motor șablon în proiectele dvs., atunci separați logica de prezentare de logica de afaceri. Unii chiar cred că motoarele de șabloane sunt create pentru designeri/dezvoltatori de aspect și că programatorii nu au nevoie de ele. Deci, totul este un mit. Un motor de șablon este un program creat pentru a face separarea logicii mai convenabilă, oferind unele funcții avansate, dar nu este în niciun caz o piatră de poticnire. Puteți folosi orice motor de șabloane sau vă puteți descurca fără unul, dar este bine să separați vizualizarea de aplicația dvs. Dimpotrivă, puteți folosi Smarty, dar în același timp încurca complet totul și împletește-l. Prin urmare, spunând că utilizați un anumit motor de șablon, transmiteți doar faptul că utilizați un anumit produs software, dar acest lucru nu indică deloc cât de bine este scrisă aplicația dvs.

Separă HTML și PHP

Aici a început totul. Oricare dintre voi își amintește de acele vremuri imemoriale când toată lumea din jur era încântată de capacitatea PHP de a pătrunde codul HTML, devenind parte din acesta. Datorită acestui fapt, înțelegerea limbii a fost mult simplificată. Multora li s-a părut chiar că HTML și PHP sunt frați, lucrând împreună, mână în mână (mulți sunt încă siguri de asta). Chiar și cei care au înțeles că PHP de fapt nu știe nimic despre HTML (la fel ca HTML despre PHP) și afișează doar text, s-au bucurat că nu au fost nevoiți să scrie o grămadă de print. Este atât de simplu!
Și această simplitate a creat o problemă.

Ciorbă

Borșul doar la prima vedere pare un haos. De fapt, borșul bine gătit este delicios. Dar dacă mai adaugi puțină varză, mai multă sare și puțină apă... Nu va avea gust. Principalul lucru în borș este să nu exagerați (scuzați jocul de cuvinte).
De fapt, nimeni nu a vrut să facă rău. Doar că noul limbaj a atras noi programatori, desigur. Sunt cele noi, flatate de simplitatea, comoditatea și puterea PHP. Pe atunci nu știam despre niciun MVC. Nu ne-am gândit la problemele de întreținere a codului, lizibilitate și stabilitate. A funcționat și ne-am bucurat sincer de asta.
Dar curând ne-am dat seama că borșul devenea lipsit de gust. Alternanțele confuze ale PHP și HTML au devenit la început prea greu de înțeles. Schimbarea designului s-a transformat în general într-un coșmar. Gândul că scrisesem deja asta odată a devenit obsesiv, dar locul unde fusese deja scris acest cod a fost extrem de greu de găsit. A fost și mai dificil să-l scoți de acolo și să-l introduci într-un proiect nou.
Dar destule versuri. În moduri diferite, am ajuns la înțelegerea că trebuie să separăm codul HTML de codul PHP. Și aici am învățat cuvântul „motor de șablon”.

Ce este un motor de șablon?

Acesta este un program conceput pentru a separa codul PHP de codul HTML. Există o părere că acest lucru este necesar pentru designeri. De fapt, nu am întâlnit niciodată designeri (scuze, designeri de layout) care să așeze șabloane imediat. Dar nu asta este ideea. De fapt, programatorilor nu le păsa de designerii de layout. Ei înșiși s-au săturat deja să satisfacă noile delicii ale designerilor, în timp ce împing tot codul.
Până în acest moment, programatorul era deja sătul de orice cod amestecat cu PHP. Cel puțin am renunțat complet la orice fel de logică în HTML. Motorul meu de șablon putea repeta bucăți de cod (blocuri), include și alte fișiere, dar nu se vorbea despre nicio logică. Mi-am petrecut întregul weekend scriind motorul meu de șabloane. Eram mândru și mă consideram cel mai corect programator. Dar proiectele au devenit curând mai complexe. Și chiar și cu toată puterea motorului meu de șabloane, HTML încă s-a infiltrat în proiectele mele în tot felul de moduri.

Logica de afaceri și de prezentare

În sfârșit ajungem la subiect. De fapt, am exagerat puțin în extragerea logicii din codul HTML. Încercând să scrie corect, ceea ce este lăudabil, programatorii au stabilit un curs pentru separarea completă a PHP de HTML. Este ca și cum doar aceste 2 limbi ar exista în lume. Dar, în realitate, PHP și HTML sunt doar instrumente. În plus, instrumentele se completează reciproc. Probabil că nu veți argumenta că HTML determină aspectul site-ului dvs. Și PHP este responsabil pentru generarea acestei vederi pe baza datelor. Dar este posibil să se separe clar PHP și HTML? Desigur că nu! PHP încă determină cum va arăta pagina ta [[*1]]. Se pare că HTML este doar o prezentare, iar PHP nu se ocupă doar de primirea datelor, ci determină și cum, unde și cât să le afișeze. Să revenim la ce am lăsat. Se pare că este imposibil să separăm PHP de HTML? O sa spun mai multe. Și nu este necesar!
Întrebarea reală nu este dacă să separă PHP de HTML, ci unde să le separă.

Logica de prezentare

Logica oricărui program poate fi împărțită în două componente - logica care primește și procesează datele[[*2]] și logica care le afișează utilizatorului. Prima se numește logica de afaceri, iar a doua se numește logica de prezentare. Este important să poți separa clar aceste 2 tipuri de logici, astfel încât să nu se amestece. În legătură cu programarea web, putem spune cu absolută încredere că HTML se referă la logica de prezentare, iar baza de date face parte din logica afacerii. Dar între ele există încă mult cod PHP. Dificultatea este de a separa acest cod. În cele din urmă am ajuns la problema care m-a determinat să scriu acest articol. De fapt, a existat de mult timp un stereotip care afirmă că PHP nu poate face parte din logica de afișare. Acest stereotip a apărut cu un motiv. Amintiți-vă că am amestecat cândva codul PHP și HTML. Apoi am învățat că nu ar trebui să facem asta, ci ar trebui să folosim motoarele de șablon. De acum înainte, tragem subconștient o linie clară între PHP și HTML, încercând să nu le amestecăm niciodată. Nu încerc să spun acum că trebuie să amesteci. Dar trebuie să înțelegeți că PHP este și responsabil pentru modul în care vor fi afișate datele, adică este direct legat de logica prezentării. Este important de înțeles că întrebarea dacă se amestecă sau nu codul PHP și HTML nu are nimic de-a face cu separarea celor două logici. Le puteți amesteca, sau le puteți separa clar și, în același timp, spuneți că aceste logici sunt bine separate în program. Înțelegerea acestui lucru este foarte importantă. Dacă separați clar PHP și logica de prezentare, atunci vă înșelați profund. De exemplu, Smarty, cel mai popular motor de șabloane, nu folosește PHP pur în șabloanele sale. Dar, cu toate acestea, el își compilează șabloanele și rezultatul este un amestec de PHP și HTML.

Două tipuri de prezentare

Dezbaterea despre utilizarea logicii în șabloane sau nu este eternă. Căci chiar și Martin Fowler vorbește despre două tipuri de strat de prezentare: reprezentare prin șablon și reprezentare cu transformare [[*3]].

Vizualizare șablon

De exemplu, toată lumea îl cunoaște pe Smarty. Datele sunt transferate în șabloanele Smarty, iar șablonul însuși determină modul de afișare a acestor date. Dar imaginați-vă că această caracteristică este deja încorporată în PHP! De fapt, spuneți-mi cum diferă PHP de șablonul Smarty? Prin ce diferă etichetele Smarty() de etichetele PHP()? Da, în esență același lucru! Îți amintești cum ți-au spus colegii mai experimentați că amestecarea codului PHP și HTML nu este bine? Deci, ai fost înșelat[[*4]]. Poate că cei care v-au spus despre asta și nu au înțeles ei înșiși că codul PHP și codul Smarty sunt frați gemeni, poate pur și simplu v-au avertizat să nu faceți greșeli mari.

PHP vs. inteligent

De fapt, PHP în mâinile unui programator fără experiență devine într-adevăr de necontrolat. Amintiți-vă despre borș. Dacă nu știi să-l gătești, devine fără gust. PHP permite prea multe și, din cauza lipsei de experiență, poate fi tentant să umpleți șabloanele PHP cu o logică variată care nu este inerentă prezentării. De exemplu, nimeni nu vă va opri să executați interogări în cod SQL. Smarty, în acest sens este mai sigur. Desigur, chiar și în Smarty poți distruge totul cu pricepere. De exemplu, scrieți o funcție care execută interogări SQL[[*5]]. Dar totuși, acest lucru necesită mult mai mult efort.
Al doilea argument împotriva șabloanelor PHP poate fi sintaxa. Am convenit deja să nu luăm în considerare problemele designerilor de layout aici. De fapt, ($var) citește mai bine decât sau, mai corect,.
O altă problemă este lipsa memoriei cache. Dar acesta este un argument numai pentru proiectele cu sarcină mare. Desigur, în acest caz este mai ușor să folosești Smarty gata făcut decât să inventezi ceva propriu.

Tot ceea ce am spus mai sus nu are scopul de a vă încuraja să abandonați Smarty și să treceți urgent la PHP simplu. Trebuie doar să înțelegeți clar că codul în HTML nu înseamnă rău. Dacă îl folosești corect, în proporțiile potrivite, atunci nu este nimic în neregulă cu el. Aceasta este doar o modalitate de a împărți aplicația în straturi și de a separa stratul de prezentare de restul. Eu însumi folosesc Smarty pentru că este convenabil pentru mine. Dar înțeleg perfect că Smarty este doar un strat convenabil care, dacă este necesar, poate fi îndepărtat.

Exemplu

Cel mai simplu mod de a trece variabile într-un șablon PHP este pur și simplu să le declarați înainte de a include șablonul în cod.

$var = "Bună, lume!"
includeți „template.php”;

Dar această metodă are o serie de inconveniente. În primul rând, acest tip de trecere a variabilei nu este transparent (uneori este dificil de găsit locul în care a fost declarată variabila).
În al doilea rând, dacă variabila nu este declarată, dar este folosită în șablon, PHP va emite o eroare la nivel de Notice, iar acest lucru nu este întotdeauna convenabil (de exemplu, Smarty nu emite notificări). În al treilea rând, cei care au folosit Smarty sunt obișnuiți să lucreze cu un obiect folosind metodele familiare Assign și Fetch. Toate aceste dezavantaje sunt ușor de rezolvat.

Uită-te la codul de mai jos și compară-l cu codul smarty. Desigur, toate metodele clasei Smarty nu sunt implementate aici, dar nu acesta este ideea. Faptul este că 90% din funcționalitatea Smarty necesară este implementată în două duzini de linii de cod. Motor de șabloane în 20 de linii! Fără a număra codul PHP în sine :)

Clasa PlainPHPView (
public $template_dir = TEMPLATES_DIR;
protejat $Vars = array();

Funcția publică __construct($template_dir = "") (
$this->template_dir = $template_dir ? $template_dir: $this->template_dir;
}

Funcția publică Assign($var_name, $var_value) (
$this->Vars[$var_name] = $var_value;
}

Funcție publică Fetch($template) (
$raporting = error_reporting(E_ALL & ~E_NOTICE);
extract($this->Vars);
ob_start();
include $this->template_dir."/".$template;
ini_set("raportare_eroare", $raportare);
return ob_get_clean();
}

Funcția publică get_template_vars($var) (

Returnează isset($this->Vars[$var])? $this->Vars[$var] : false;
}
}

Puteți utiliza acest cod în același mod ca smarty. Singura diferență este în sintaxa șablonului. Dar este foarte ușor să te obișnuiești.

$var = "Bună, lume!"
$view = new PlainPHPView("./");
$view->Assign("var", $var);
print $view->Fetch("template.php");

Transform View

Pe lângă dezbaterea dacă să interferezi cu PHP și HTML sau să folosești Smarty, există o altă dezbatere nu mai puțin fundamentală, dar nu mai puțin inutilă. Dezbaterea este dacă să punem vreo logică în șabloane.


Nu există o logică explicită în șabloanele bazate pe modelul Reprezentare cu transformare[[*6]]. Acesta este HTML aproape pur. Dar înainte de ieșire, acest HTML este transformat folosind o anumită logică și numai după aceea este dat clientului. Adică, reprezentarea este determinată nu numai de șablonul în sine, ci și de codul special care procesează acest șablon. Martin Fowler oferă exemplul transformării XSLT a datelor XML. Vreau să dau un exemplu mai aproape de realitate: FastTemplate.
În motoarele de șablon precum FastTemplate, logica este determinată de cod. Șablonul în sine conține doar HTML și markeri speciali care marchează zonele șablonului care trebuie procesate. „Translatorul” însuși citește șablonul și îl convertește în HTML final.
Cu toate acestea, în șabloanele complexe, este foarte dificil să evitați separarea completă a PHP de HTML. Totuși, de exemplu, codul de legătură sau elementele de formular sunt mai ușor de format în scriptul de conversie în sine. Și aceasta nu este o decizie rea. De fapt, atât șablonul, cât și „rezolvatorul” lucrează împreună și locuiesc împreună în stratul de prezentare. Dar atunci când utilizați acest model, este și mai important să puteți separa corect straturile, astfel încât acestea să nu se amestece. De exemplu, ar fi bine să desemnăm „convertorul” ca o clasă, abstragându-l astfel de restul codului.

Ajutoare

În oricare dintre abordări, poate apărea o situație când este necesar să se genereze vederi tipice în diferite șabloane.

De exemplu, generarea de link-uri sau elemente de formular. În orice caz, cel mai convenabil este să scoateți acest cod din șablon și să îl formatați ca funcție sau clasă sau ca metodă. De exemplu, sistemul de plugin Smarty. Asemenea funcții sunt numite „ajutoare” sau Ajutoare. De fapt, încercați să scrieți cod într-un șablon care generează un calendar. Sunt sigur că o poți face. Dar dacă calendarul este necesar într-un alt șablon sau chiar într-un proiect? Copy+Paste este cu siguranță o soluție, dar nu o soluție. Este mult mai ușor să formatați un astfel de cod ca metodă de clasă. Desigur, acest lucru va face mai dificilă schimbarea designului, deoarece acum aspectul site-ului dvs. depinde nu numai de șablon. Dar nu uitați că o prezentare nu este doar un șablon, ci întregul set de clase și funcții aflate în stratul de prezentare.

Deci, ce este un motor de șablon?

După cum am spus, motorul de șablon este un mit. Mitul nu este în sine. Este un mit în contextul în care acest cuvânt este adesea folosit. Probabil ați fost întrebat la un interviu înainte de a fi angajat despre ce motor de șablon utilizați. Răspunsul „niciunul” reduce foarte mult șansele de a fi angajat. De fapt, angajatorul avea ceva puțin diferit în minte. A vrut să vă întrebe cum, și nu cu ce, împărțiți logica aplicației în straturi. Dar în mintea multora, din păcate, motorul șablonului și logica prezentării sunt cuvinte sinonime, cu excepția cazului în care, desigur, acest din urmă termen este chiar cunoscut interlocutorului tău. Încercați să răspundeți că nu utilizați motoare de șablon, ci folosiți un amestec de PHP și HTML. 5 la 1 că nu te vor lua :)

Concluzie

Îți amintești cum cineva înțelept a remarcat că istoria tinde să se miște în spirală, repetându-se adesea, dar la un nivel superior? Obișnuiam să amestecăm codul PHP și HTML, apoi am aflat că este rău, dar acum se dovedește că nu este atât de rău. Odată am crezut că logica din șabloane este rea, dar acum scriu un articol despre cum acestea sunt doar una dintre abordări.
Scopul meu în acest articol a fost să nu vă schimb părerile. Dacă îți place Smarty, nu renunța la el. Dacă îți place FastTemplate și motoarele similare, acesta este și dreptul tău. Fiecare alegere are argumentele sale pro și contra. Principalul lucru este că alegerea soluției se bazează pe criterii clare și pe deplină conștientizare a ponderii acestora în selecția largă de opțiuni disponibile. Ghidat de stereotipuri impuse, te privezi de dreptul de a face o astfel de alegere. Sper că acest articol vă va face să aruncați o privire mai amplă asupra problemelor cu care vă confruntați în sarcina dificilă de a crea sisteme web.

- [[#1]] De exemplu, de câte ori să afișați acest sau acel bloc, afișați text în 2 coloane, afișați un tabel în care rândurile au culori diferite... va fi dificil să obțineți astfel de efecte cu HTML obișnuit .

[[#2]] O aplicație este de obicei împărțită în 3 straturi, dar în acest articol vom împărți aplicația în 2 straturi, logica de prezentare și orice altceva.

[[#3]] Fowler vorbește despre trei soluții tipice, dar a treia este o combinație a primelor două. Pentru literaliști, voi explica că Smarty aparține tocmai celui de-al treilea tip, combinând soluțiile standard „Reprezentare prin șablon” și „Reprezentare cu transformare”.

[[#4]] Smarty face exact acest lucru, compilând șabloanele într-un amestec de cod PHP și HTML.

[[#5]] Apropo, Doamne ferește să-ți impun alt stereotip. Stratul de prezentare poate selecta în mod independent datele din baza de date, ocolind stratul logic de afaceri și chiar poate transfera în mod independent aceste date, de exemplu, pentru calcule complexe, în stratul de domeniu. Astfel de șabloane sunt numite și active. Nu soluția determină arhitectura, ci arhitectura care necesită soluții :)

[[#6]] Mai există logică. Dar aceasta este o logică implicită.