Webcity.pl


  Język marketingu

  Czym jest marketing ...

  Piszemy Engine cz. 4

  Wyrażenia w PHP

  Piszemy Engine cz. 3

 

 02.02.06 - [new] E-video - artykuł

 30.01.06 - [update] Artykuł o sesjach

 18.12.05 - [update] PDO - artykuł

 19.08.05 - [new+upd] Aktualizacja materia...

 26.04.05 - [update] Nowy artykuł



  Pomocy WML
[php]Sesje nie działają, ...
[actionscript 2.0] [flash...
Problem z talicami w php
[ocena] llll.pl darmowe a...
Kamera na stronie interne...
Kamera na stronie interne...
[xml] Jak wyciągnąć dane
Wizualizacja w JS - POMOC
Web Developer - stała / f...

... i wiele innych wątków na forum ›

Partnerzy
› allRSS.info - katalog zasobów RSS
› iloveflyer.org - webdesign
› webserv.pl - serverpack
› skryptoteka.pl - mnóstwo skryptów
› vel.pl - hosting
› TelePraca.net - pracuj swobodnie
› PHP Solutions - magazyn PHP
› HELION - wydawnictwo informatyczne

Ksišżka dnia

CityMag
Wpisz swój e-mail, aby zaprenumerować nasz Magazyn, który zawiera najnowsze informacje ze świata i najciekawsze teksty.
 

Szukasz czegoś?
Nasza wyszukiwarka znajdzie wszystko, czego szukasz.
 

Szukanie zawansowane


  Reklama
  Redakcja
  Hosting
  Kanał

© WebCity.pl Team
 
 
  Forum Forum
Kursy Kursy
Porady Porady
Recenzje Recenzje
Newsy Newsy
Katalog stron WWW Katalog
Skrypty PHP Skrypty
Download Oferty i praca
Artykuły:
 Teoria
 Praktyka
 Promocja
 Inne
 

 Webcity.pl |

Piszemy Engine cz. 2

Autor: Zyx
   Witam was w drugiej części poradnika pt. "Piszemy engine". Tym razem zajmiemy się już bardziej zaawansowanymi rzeczami - napiszemy system szablonów. W planach miała być tutaj jeszcze główna klasa enginu, lecz z powodu wielkości kodu systemu szablonów, przesunąłem ją do trzeciej części (która powinna ukazać się wraz z tą). A więc co? Zaczynamy?
   Zapewne słyszałeś już gdzieś o idei oddzielenia kodu HTML serwisu, od jego kodu PHP. Poprzez jej wdrożenie prace nad całością stają się łatwiejsze - programiści pracują na swoich plikach, designerzy na swoich i każdy jest happy - nikt nikomu nie wchodzi w paradę. Jednak dróg do osiągnięcia tego jest kilka. Możemy np. przygotować sobie specjalne funkcje wyświetlające poszczególne części strony, które będą potem w odpowiednich miejscach wywoływane. Jest jednak bardziej elegancki, lecz trudniejszy do wykonania sposób. Chodzi właśnie o systemy szablonów. Są to właściwie zaawansowane interpretery, które potrafią wychwycić z kodu HTML specyficzne dla siebie znaczniki. Dzięki nim wiedzą, że w tym miejscu należy wstawić dane ze skryptu, w tym sprawdzić warunek itp. My zajmiemy się właśnie tym sposobem. Polecam zapoznanie się z artykułem "Szablony (Templates)", gdzie opisałem tworzenie prostego parsera.
   Zagadnieniem systemów szablonów interesuję się od baaaaaaaaardzo dawna, testowałem wiele możliwych wariantów i technologii używanych do ich
utworzenia, a spod mojej klawiatury wyszło już około 8, czy 10 różnych interpreterów. Masz więc pewność, iż zagadnienie to opisze Ci tzw. "człowiek z doświadczeniem" :). Podane niżej rozwiązanie opracowałem całkiem niedawno, bo jakieś 1,5 miesiąca temu. Jest ono jednak bardzo wydajne(kompilator działałby kilkakrotnie wolniej, gdyby użyć "zwykłej" metody kompilacji plików *.TPL), a przy tym daje potężne możliwości.
   Zastanówmy się wpierw nad składnią plików *.TPL. Zdecydowałem się na maksymalną zgodność z szablonami dla phpBB 2.0 (100%), oraz na bardzo dużą z phpBB 2.2, które jest dopiero w fazie projektowania (zgodność 80 - 90%). Na wszelki wypadek opiszę tu jednak, co i jak. Plik szablonu jest w rzeczywistości zwykłym plikiem HTML, w którym znajdują się <b>bloki</b> i <b>komendy</b>. Bloki są ograniczone klamrami { i }, oraz zawierają nazwę. Ich zadanie polega na wprowadzaniu do kodu wyników działania skryptu. Komendy natomiast zamknięte są w komentarzach języka HTML: <!-- i --> i niosą z sobą informację o sposobie przetworzenia danego kawałka kodu. Dane zawarte w komendzie koniecznie muszą być umieszczone w odstępie jednej spacji od znaczników komentarza. Teraz zajmijmy się możliwościami. Na pierwszy ogień pójdą komendy, oraz dawane przez nie możliwości:
   - Sekcje (w poprzedniej edycji zwane "subsekcjami") - jest to pewien rodzaj pętli, która wykonuje podany kod HTML tyle razy, ile razy wprowadzimy dla niego dane. Przykładowo: mamy do wyświetlenia 10 newsów. Wprowadzamy więc kolejno informacje o nich, w pliu *.TPL zamykamy kod odpowiedzialny za wygląd pojedynczego newsa w sekcję, po czym uruchamiamy parser i patrzymy, jak ładnie on to wszystko połączył w całość :). Sekcja rozpoczyna się komendą <!-- BEGIN nazwa_sekcji -->, a kończy <!-- END nazwa_sekcji -->. Może ona leżeć zarówno bezpośrednio w dokumencie, jak i w innej sekcji (wtedy jest tzw. sekcją zagnieżdżoną).
   - Zmienne - jest to namiastka zmiennych znanych z PHP. Jedyną różnicą jest to, iż informację o jej wartości musimy ustalić na sztywno - nie można stosować żadnych wyrażeń. Za ich inicjację odpowiada komenda <!-- VAR nazwa wartosc -->
   - Wstawki PHP - Nasz system szablonów powinien być nowoczesny i przygotowany na różne dziwne zachcianki programistów :). Dlatego mogą oni w prosty sposób pomiędzy komendami <!-- PHP_START --> i <!-- PHP_END --> umieszczać wstawki kodu PHP.
   - Instrukcja warunkowa IF - Za jej pomocą będziemy mogli warunkowo kompilować szablon. Do dyspozycji mamy cztery komendy: <!-- IF wyrażenie -->, <!-- ELSEIF wyrażenie -->, <!-- ELSE --> i <!-- ENDIF -->. Ich znaczenia można domyślić się po nazwach. Trochę większy kłopot jest z wyrażeniami, które trzeba do nich wprowadzić. Jako iż z oczywistych powodół nie może to być wyrażenie PHP, musimy sami określić jego składnię: wyrażenie zatem składa się z dowolnych bloków (tyle że tym razem nie ograniczonych klamrami), oraz operatorów. Oto ich lista:

+----------+-------------------+
| Operator | Odpowiednik w PHP |
+----------+-------------------+
| eq       | ==                |
| ne       | !=                |
| neq      | !=                |
| lt       | <                 |
| le       | <=                |
| lte      | <=                |
| gt       | >                 |
| ge       | >=                |
| gte      | >=                |
| and      | &&                |
| or       | ||                |
| not      | !                 |
| mod      | %                 |
| div      | /                 |
| add      | +                 |
| sub      | -                 |
| mul      | *                 |
+----------+-------------------+

Proszę mnie nie katować za takie powalone nazewnictwo - jeśli mamy zachować maksymalną zgodność z phpBB 2.2, to tak musi właśnie zostać. A wracając do tematu, oto przykłady poprawnych wyrażeń:

(BLOK eq 1) and (BLOK2 neq 4)
@zmienna neq 15
sekcja.BLOK lt 7
not sekcja.BLOK


   - Dołączanie zewnętrznych plików realizujemy za pomocą komendy <!-- INCLUDE uchwyt -->. Uchwyt jest to identyfikator dla pliku, który ustawia sobie sam skrypt. Możemy więc dołączać tylko te pliki, które przewidział dla nas programista.

A oto i rodzaje bloków:
   - zwykły blok - jest to po prostu nazwa ograniczona klamrami: {BLOK}, która w momencie parsowania zostanie zamieniona na daną ze skryptu.
   - zmienna - Za pomocą tego bloku można odwoływać się do utworzonych zmiennych, które poprzedzone są znakiem małpy, np. {@zmienna}.
   - blok sekcji - Dzięki niemu bez problemu pobierzemy dane należące do danej sekcji. Oto składnia: {sekcja1.sekcja2. ... .BLOK}.

   Po takim wstępie warto zabrać się do pracy. Skrypt łącznie posiada 9 kb wielkości, a zawarta jest w nim klasa Template, której egzemplarz warto sobie zainicjować zaraz po załadowaniu jej. A wszystko zaczęło się od nagłówka:

<?php
/*
*****************************************************************************
*    Fillar WebSystem 1.0.0
* ========================================
*    Fillar Systems 2003
*****************************************************************************
*
* -> Template Parser
* -> Written by Tomasz "ZyxwvU" Jędrzejewski
* -> Date started: 18-4-2003
*
*   -> Version: 1.0.0
*****************************************************************************
*/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
/*
* Fast and Advanced Template Class. 90% compability with phpBB 2.2 parser and
* 100% compability with phpBB 2.0 parser.
*/
   class Template{
      var $root;
      var $files;

      var $compiled;
      var $uncompiled;

      var $_block_data;
      var $_variables;
      var $section_nesting_level;
      var $section_names;

      var $file;

Na początku deklarujemy sobie kilka potrzebnych pól. $root określa katalog, w którym znajdują się pliki *.TPL. $files to lista powiązań uchwytów z plikami. W $compiled zapisywany jest wynik działania parsera, a do $uncompiled ładowany jest cały kod przed rozpoczęciem parsowania. W $_block_data znajdują się dane o blokach, a w $_variables o zmiennych. $section_nesting_level i $section_names są polami potrzebnymi do sprawdzania, czy sekcje zamykane są we właściwej kolejności. $file zawiera nazwę ostatnio załadowanego pliku tak, by w przypadku próby przeparsowania jeszcze raz tego samego, nie wczytywać szablonu na nowo z dysku. PrzejdĄmy teraz do pierwszych metod: konstruktora, tej ustawiającej katalog ROOT, oraz tworzącej uchwyt dla pliku:

      function Template($root){
         $this -> set_root($root);
         $this -> files = array();
         $this -> compiled = '';
         $this -> uncompiled = '';
      } // end Template();

      function set_root($root){
         if(is_dir($root)){
            $this -> root = $root;
         }
      } // end set_root();

      function set_filename($handle, $file){
         $this -> files[$handle] = $file;
      } // end set_filename();

Kod ten jest bardzo prosty, nie powinien sprawić Ci większych problemów z analizą. Warto wspomnieć, iż jeśli jesteś szczęśliwym posiadaczem PHP 5 (w chwili pisania artykułu w fazie alpha), powinieneś zmienić nazwę konstruktora z "Template" na "__construct".

   Następnym krokiem będą metody odpowiedzialne za wprowadzanie danych do tablicy bloków. Acha... naturalnie przepraszam za angielskie komentarze, ale system ten wchodzi w skład pewnego mojego projekciku nastawionego także na rynki "zachodnie":

      function assign_block($name, $value){
         $this -> _block_data['.'][0][$name] = $value;
      } // end assign_block();

      function assign_blocks($array){
         $this -> _block_data['.'][0] = $array;
      } // end assign_blocks();

      function assign_section_blocks($blockref, $array){
         if(strstr($blockref, '.')){
            // Nested block.
            $blocks = explode('.', $blockref);
            $blockcount = sizeof($blocks) - 1;

            $str = '$this -> _block_data';
            for ($i = 0; $i < $blockcount; $i++){
               $str .= '[\''.$blocks[$i].'\']';
               eval('$cnt = sizeof('.$str.') - 1;');
               $str .= '['.$cnt.']';
            }
            // Now we add the block that we're actually assigning to.
            // We're adding a new iteration to this block with the given
            // variable assignments.
            eval($str.'['.$blocks[$blockcount].'][] = $array;');
         }else{
            // Top-level block.
            // Add a new iteration to this block with the variable assignments
            // we were given.
            $this -> _block_data[$blockref][] = $array;
         }

         return true;
      } // end assign_section_blocks();

Warta analizy jest metoda assign_section_blocks() - pozwala ona bowiem wprowadzać dane dla bloków należących do jakiejś sekcji. Pierwszy parametr jest adresem do sekcji, którą chcemy uzupełnić, natomiast drugi to tablica asocjacyjna z blokami. Klucz to nazwa bloku, a wartość to dane, na jakie ma być on zamieniony. Jeśli podamy adres do sekcji globalnej, nastąpi szybkie przypisanie wartości. Problem pojawia się jednak, gdy chcemy coś dodać do sekcji zagnieżdżonej, ponieważ musimy obliczać za każdym razem, ile elementów posiada kolejna sekcja. Rozwiązałem go jednak poprzez sprytne połączenie funkcji eval(), oraz pętli for(). Zajmijmy się teraz ostatnią metodą publiczną - parse().

      function load_file($file){
         if(file_exists($this -> root.'/'.$file)){
            $f = fopen($this -> root.'/'.$file, 'r');
            $this -> uncompiled = fread($f, filesize($this -> root.'/'.$file));
            fclose($f);
         }else{
            die('Template error [load_file]: '.$this -> root.'/'.$file.' nieznaleziony.');
         }
      } // end load_file();

      function parse($handle){
         $this -> compiled = '';
         if($handle != $this -> file){
            $this -> load_file($this -> files[$handle]);
            $this -> file = $handle;
         }

         $this -> compile();

         eval($this -> compiled);
      } // end parse();

Metoda load_file() ma za zadanie wczytać Ąródło podanego pliku do pamięci, natomiast parse() służy do ostatecznego wykonania czynności parsowania. Jako parametr podajemy nazwę uchwytu pliku, który chcemy obrobić. Zauważ, iż sam mechanizm kompilujący znajduje się dopiero w nienapisanej jeszcze metodzie compile(). Rozwiązanie takie ma swoje zalety - przykładowo jeśli będziemy chcieli wmontować w parser mechanizm cache (tak, by zapisywało skompilowane do postaci kodu PHP strony, by potem nie kompilować ich jeszcze raz), unikniemy niepotrzebnego bałaganu. Ponadto mamy pewność, iż metoda jest wewnętrznie spójna :).
   Następne dwie metody będą odpowiedzialne za obsługę komendy INCLUDE. Jest ona przetwarzana oddzielnie z bardzo prostego powodu - cały kod z dołączanego pliku także musi przejść przez te same etapy, co główny kod, a gdybyśmy tak wrzucili go tam, gdzie resztę, to dołączane pliki opuściłyby etap neutralizowania apostrofów, że o ominięciu wstawiania bloków nie wspomnę :).

      function assign_includes(){
         $this -> uncompiled = preg_replace_callback('#<!-- INCLUDE (.*?) -->#s',
         array($this, 'include_source'),
         $this -> uncompiled);
      } // end assign_includes();

      function include_source($matches){
         $file_name = $this -> files[$matches[1]];

         if(file_exists($this -> root.'/'.$file_name)){
            $f = fopen($this -> root.'/'.$file_name, 'r');
            $source = fread($f, filesize($this -> root.'/'.$file_name));
            fclose($f);
         }else{
            die('Template error [INCLUDE]: '.$this -> root.'/'.$file_name.' nieznaleziony.');
         }
         return $source;
      } // end include_source();

assign_includes() ma za zadanie wyłapać wszystkie komendy <!-- INCLUDE (.*?) --> z kodu *.TPL. Zauważ, iż użyłem do tego funkcji preg_replace_callback. Jest to specjalna odmiana zwykłego preg_replace, lecz daje nam ciekawą możliwość. Mianowicie, gdy znajdzie tekst pasujący do podanego wyrażenia, wywołuje odpowiednią funkcję, do której przekazuje te dane (kolejno: całe wyrażenie, poszczególne bloki, czyli to w nawiasach itp.). Funkcja ta jest drugim parametrem wywołania preg_replace_callback. Aby dostać się do metody klasy, musieliśmy zastosować pewną sztuczkę, mianowicie wysłać tablicę, której pierwszy element będzie wskaĄnikiem $this, a drugi nazwą metody do wywołania. W tym wypadku używamy 'include_source', która przetwarza dane z wyrażenia, po czym wczytuje plik i zwraca go. Zwrócony tekst jest wstawiany zamiast komendy <!-- INCLUDE (.*?) -->.

   Metoda Compile(), serce całego mechanizmu. Wbrew pozorom bardzo prosta - składa się z jednej prościutkiej pętli i szeregu wyrażeń regularnych :). Rozwiązanie to jest odmienne od konkurencji (która najpierw pracowicie pobiera każdą komendę, potem osobno ją za pomocą PHP przetwarza, generując dla niej kod PHP), a co ważniejsze, wydajniejsze. UWAGA: W mechaniĄmie ukryłem pewien niegroĄny, ale dosyć trudny do wykrycia błąd specjalnie, by ktoś go znalazł. Na odpowiedzi czeka mój e-mail - należy przysłać wyjaśnienie błędu i kod Ąródłowy z patchem :). Mój brat z konkursu" jest wyłączony :).

      function compile(){
         $this -> assign_includes();

         $this -> compiled = str_replace(array(
               '\\',
               '\''
               ), array(
               '\\\\',
               '\\\''
         ), $this -> uncompiled);

         // Replace block data
         if(preg_match_all('#\{(((([a-zA-Z0-9\-_]+?\.)*?)([a-zA-Z0-9_]+?))|(@[a-zA-Z0-9_]+?)|(([a-zA-Z0-9_]+?)@([a-zA-Z0-9_]+?)))\}#s', $this -> compiled, $found)){
            foreach($found[1] as $match){
               $match_table[] = '\'.'.$this -> generate_block_ref($match).'.\'';
            }
            $this -> compiled = str_replace($found[0], $match_table, $this -> compiled);
         }

         $this -> compiled = '$this -> compiled = \''.
            preg_replace_callback('#<!-- (IF|ELSEIF|BEGIN|END) (.*?) -->#s', array($this,'master_tags'),
               preg_replace(array(
                  '#<!-- VAR (.*?) "(.*?)" -->#s',
                  '#<!-- ELSE -->#s',
                  '#<!-- ENDIF -->#s',
                  '#<!-- PHP_START -->(.*?)<!-- PHP_END -->#s'
               ), array(
                  '\'; $this -> _variables[\'@\\1\'] = \'\\2\'; $this -> compiled .= \'',
                  '\'; }else{ $this -> compiled .= \'',
                  '\'; } $this -> compiled .= \'',
                  '\'; \\1 $this -> compiled .= \''
               ), $this -> compiled)).'\';';
      } // end Compile();

Przypominam, iż parser działa na zasadzie: przetwórz plik *.TPL na kod PHP, a następnie wykonaj go funkcją EVAL. Tu widać użycie wyrażeń regularnych do realizacji pierwszego zadania - cztery komendy zamieniane są automatycznie na kod PHP, a cztery (IF,ELSEIF,BEGIN i END) przekazywane poprzed preg_replace_callback do specjalnych metod je przetwarzających. Napiszemy je troszkę dalej, teraz należy się zająć kodem przekształcającym odwołania do bloków sekcji, np. sekcja.BLOK na wykonywalny kod PHP, czyli $this -> _block_data['sekcja'][$i]['BLOK].

      function generate_block_ref($ref){
         if($ref{0} == '@'){
            return '$this -> _variables[\''.$ref.'\']';
         }

         $namespace = explode('.', $ref);
         if(count($namespace) > 1){
            $str = '$this -> _block_data';

            for($i = 0; $i < count($namespace) - 1; $i++){
               $str .= '[\''.$namespace[$i].'\'][$__'.$namespace[$i].']';
            }
            $str .= '[\''.$namespace[$i].'\']';
         }else{
            $str = '$this -> _block_data[\'.\'][0][\''.$ref.'\']';
         }
         return $str;
      } // end generate_block_ref();

      function generate_blockcount_ref($ref){
         $namespace = explode('.', $ref);

         $str = '$this -> _block_data';

         for($i = 0; $i < count($namespace) - 1; $i++){
            $str .= '[\''.$namespace[$i].'\'][$__'.$namespace[$i].']';
         }
         return $str .= '[\''.$namespace[$i].'\']';
      } // end generate_blockcount_ref();

Metody mamy dwie - pierwszą wykorzystuję do przekształcania bloków w nawiasach klamrowych, a druga jest przystosowana specjalnie do użycia wraz z inicjacją nowych sekcji.

   Kolejna metoda, master_tags() generuje kod PHP dla bloków IF, ELSEIF, BEGIN i END, jest więc wywoływana przez funkcję preg_replace_callback z metody compile().

      function master_tags($matches){
         switch($matches[1]){
            case 'IF':
               return $this -> parse_if($matches[2], 0);
            case 'ELSEIF':
               return $this -> parse_if($matches[2], 1);
            case 'BEGIN':
               $this -> section_nesting_level++;
               $this -> section_names[$this -> section_nesting_level] = $matches[2];
               $data = implode('.', $this -> section_names);
               return '
                  \'; $a_'.$matches[2].' = count('.$this -> generate_blockcount_ref($data).') - 1;
                  for($__'.$matches[2].' = 0; $__'.$matches[2].' <= $a_'.$matches[2].'; $__'.$matches[2].'++){
                  $this -> compiled .= \'
                  ';
            case 'END':
               if($this -> section_names[$this -> section_nesting_level] == $matches[2]){
                  unset($this -> section_names[$this -> section_nesting_level]);
                  $this -> section_nesting_level--;
                  return '\'; } $this -> compiled .= \'';
               }else{
                  die('Template error: Nie można zamknąć sekcji, gdy jest pod-sekcje są otwarte ['.$matches[2].']');
               }

         }
      } // end master_tags();

No i pozostała nam ostatnia metoda - parse_if() odpowiedzialna za przetwarzanie naszych kochanych operatorów, odwołań do bloków i zmiennych, na kod PHP :). Część kodu, wzorem twórców phpBB, zaczerpnąłem ze Smarty'ego. Wyrażenie regularne wychwytuje wszystkie fragmenty wyrażenia, zwane fachowo tokenami (operatory, bloki, zmienne i wartości stałe), po czym przekazuje je do instrukcji SWITCH:

      // This is from Smarty/phpBB 2.2
      // with small modifications
      function parse_if($pattern, $what){
         /* Tokenize args for 'if' tag. */
         preg_match_all('/(?:
               "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
               \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
               [(),] |
               [^\s(),]+)/x', $pattern, $match);

         $tokens = $match[0];
         $is_arg_stack = array();

         for ($i = 0; $i < count($tokens); $i++){
            $token = &$tokens[$i];

            switch ($token){
               case 'eq':
                  $token = '==';
                  break;

               case 'ne':
               case 'neq':
                  $token = '!=';
                  break;

               case 'lt':
                  $token = '<';
                  break;

               case 'le':
               case 'lte':
                  $token = '<=';
                  break;

               case 'gt':
                  $token = '>';
                  break;

               case 'ge':
               case 'gte':
                  $token = '>=';
                  break;

               case 'and':
                  $token = '&&';
                  break;

               case 'or':
                  $token = '||';
                  break;

               case 'not':
                  $token = '!';
                  break;

               case 'mod':
                  $token = '%';
                  break;

               case 'div':
                  $token = '/';
                  break;

               case 'add':
                  $token = '+';
                  break;

               case 'sub':
                  $token = '-';
                  break;

               case 'mul':
                  $token = '*';
                  break;

               case '(':
                  array_push($is_arg_stack, $i);
                  break;

               default:
                  if(preg_match('#\{(((([a-zA-Z0-9\-_]+?\.)*?)([a-zA-Z0-9_]+?))|(@[a-zA-Z0-9_]+?)|(([a-zA-Z0-9_]+?)@([a-zA-Z0-9_]+?)))\}#s', $token, $varrefs)){
                     $token = $this->generate_block_ref($token);
                  }elseif($token{0} == '@'){
                     $token = '$this -> _variables[\''.$token.'\']';
                  }
                  break;
               }
            }
            return (($what) ? '} elseif (' : ' \'; if (') . (implode(' ', $tokens) . ') { $this -> compiled .= \'' . "\n");
         }
      } // end parse_if();

?>

No i to tyle, jeśli chodzi o sam kod. Jest on już gotowy do użycia, lecz to zagadnienie omówię w następnej, trzeciej części PE.

   Na forum często spotkałem się z różnymi modyfikacjami starego systemu szablonów tu przedstawionego, dlatego cały proces tym razem opisuję. Ogólnie całość polega na dodaniu odpowiedniego wyrażenia do tabeli dla preg_replace w metodzie "compile()". Jeśli kod nie wymaga zbytnich przekształceń, wrzucamy to do preg_replace, natomiast gdy przy okazji trzeba sprawdzić jakieś zależności, by zezwolić na zamianę, wywołanie wrzucamy do preg_replace_callback - dopisujemy w wyrażeniu po znaku | nazwę naszej instrukcji, a dalszy kod leci do metody master_tags().
   Podobnie rzecz się ma z dodawaniem nowych operatorów do instrukcji IF/ELSEIF - dodajemy nową klazulę CASE z symbolem operatora, a w jej kodzie do zmiennej $token wprowadzamy symbol tegoż operatora w PHP.

   Zapraszam więc do czytania następnej części.

Artykuł reedytowany

Powrót

 
 
Twój domowy serwer!