Projektując aplikację internetową dość często korzysta się z plików konfiguracyjnych zawierających chociażby dane do połączenia z bazą. Sposób zapisu tych danych jest zależny od formatu pliku z konfiguracją. Dość często formatem tym jest XML ze względu na możliwość uzyskiwania praktycznie dowolnej struktury pliku. Niestety wadą formatu XML jest często przerost formy nad treścią czego wynikiem jest spory narzut informacji o strukturze pliku w porównaniu do samych danych, które mają być wykorzystane.

Istnieją rozwiązania alternatywne takie jak np. format INI znany z plików konfiguracyjnych aplikacji pracujących w systemie MS Windows. Format ten ma zdecydowanie mniejszy narzut jednak posiada on płaską strukturę czyli nie pozwala tworzyć struktur drzewiastych co może powodować spore problemy przy odczycie. Podobny problem dotyczy formatu plików conifguracyjnych spotykanych w systemach linuksowych.

Jest jednak pewne rozwiązanie które niejako łączy zalety powyższych pozbawiając ich przy tym głównych wad. Format o którym mowa to YAML, którego strona domowa znajduje się pod adresem http://yaml.org. Format ten przypomina pliki INI jednak jest bardziej czytelny i pozwala na tworzenie skomplikowanych struktur danych minimalizując przy tym narzut struktury nad zawartością.
Format ten powstał w 2001 roku a skrót początkowo oznaczał Yet Another Markup Language. Z czasem nazwa została zmieniona na YAML Ain't Markup Language by lepiej oddać zastosowanie języka. Przykład pliku konfiguracyjnego w formacie YAML:

CODE:
  1. logEvent:    Oz-Ware Purchase Invoice
  2. date:        2007-08-06
  3. customer:
  4.     given:   Dorothy
  5.     family:  Gale
  6.    
  7. items:
  8.     - part_no:   A4786
  9.       descrip:   Water Bucket (Filled)
  10.       price:     1.47
  11.       quantity:  4
  12.  
  13.     - part_no:   E1628
  14.       descrip:   High Heeled "Ruby" Slippers
  15.       price:     100.27
  16.       quantity:  1
  17.  
  18. bill-to:  &id001
  19.     street: |
  20.             123 Tornado Alley
  21.             Suite 16
  22.     city:   East Westville
  23.     state:  KS
  24.  
  25. ship-to:  *id001   
  26.  
  27. specialDelivery: >
  28.     Follow the Yellow Brick
  29.     Road to the Emerald City.
  30.     Pay no attention to the
  31.     man behind the curtain.

Format YAML umożliwia przechowywanie prostych ciągów znaków, liczb i bardziej skomplikowanych danych takich jak tablice asocjacyjne czy dane binarne. Ich zapis jest bardzo czytelny i wydaje się być dość naturalny dlatego znakomicie nadaje się do przechowywania danych konfiguracyjnych. Pełna specyfikacja znajduje się na stronie http://yaml.org/spec/current.html. W wielu językach istnieją biblioteki ułatwiające odczyt danych z formatu YAML i dostępne są na stronie: http://en.wikipedia.org/wiki/YAML#Implementations. Dla PHP dostępny jest moduł z repozytorium PECL Syck oraz biblioteka Spyc.

Wbudowany w PHP mechanizm sesji ze względu na łatwość użycia jest zdecydowanie najbardziej popularnym sposobem przechowywania zmiennych między kolejnymi przeładowaniami strony. Niestety mechanizm ten ze względu na swoją prostotę nie jest do końca bezpieczny. Istnieją różne sposoby zabezpieczenia sesji i własne mechanizmy obsługi zmiennych sesyjnych jednak najczęściej są one dosyć skomplikowane. Ja chciałem przedstawić bardzo prosty bo wbudowany sposób uczynienia sesji bardziej bezpiecznymi.

Jak wiadomo najprostszym sposobem przechwycenia sesji np. zalogowanego użytkownika jest pobranie identyfikatora sesji SESSID i zwykłe doklejenie go do adresu. Takie działania spowoduje, że użytkownik, który dokonał takiego wklejenie staje się dla serwera tym samym użytkownikiem co ten prawdziwy. Oczywiście można nieco utrudnić taki atak poprzez włączenie opcji session.use_only_cookies jednak nadal istnieje możliwość skorzystania z cudzej sesji. Wydaje się, że dobrym rozwiązaniem byłaba zmiana identyfikatora sesji przy każdorazowym przeładowaniu strony bądź żądaniu do serwera poprzez obiekt XMLHttpRequest poprzez funkcję session_regenerate_id(). Wówczas jednak na serwerze zaczęłaby się pojawiać ogromna ilość bezużytecznych plików starych sesji. Rozwiązaniem okazuje się być wprowadzony w PHP od wersji 5.1 parametr powyższej funkcji typu bool określający czy usuwać stare pliki sesji. Dzięki temu wbudowany w PHP mechanizm sesji staje się bezpieczniejszy bo jeśli nawet atakującemu uda się przechwycić id sesji na niewiele mu się on przyda bo po ponownym przeładowaniu strony otrzyma on nowy i przy okazji inny niż atakowanego użytkownika identyfikator.

Podsumowując za pomocą funkcji session_regenerate_id(true) możemy zabezpieczyć sesję przed próbą wykorzystania jego identyfikatora przez innego użytkownika. A dzięki parametrowi true unikniemy zbędnego gromadzenia starych plików sesji.

Aplikacje internetowe korzystając z technologii AJAX prawie zawsze muszą wymieniać dane pomiędzy interfejsem użytkownika (JS, Flash itp) a serwerem (PHP, ASP itp).

Jak wiadomo nie można wprost przesłać np. tablicy czy obiektu z funkcji JS do skryptu PHP korzystając z obiektu XMLHttpRequest gdyż struktura takiej tablicy czy obiektu zostanie utracona. Należy więc dane jakoś przekształcić a najlepiej do pojedynczego łańcucha znaków. Dobrze byłoby gdyby po stronie przeglądarki w skryptach JS nie trzeba było korzystać z dodatkowych bibliotek niepotrzebnie powiększających ciężar strony. Ideałem byłoby gdyby format był zwięzły i w miarę czytelny. Spełnienie wszystkich tych życzeń wydaje się być nierealne a jednak!

Doskonałym rozwiązaniem okazuje się być format JSON (wymawiane jak imię "Jason" -- j?'s?n) oznacza JavaScript Object Notation czyli notacja obiektów JavaScript.
Po pierwsze niezależnie od typu dane po zakodowaniu są zawsze pojedynczym ciągiem znaków np.:

JavaScript:
  1. var jsonData = '{"a":{b:["c","d","e"],"f":{"g"}}}';

Po drugie aby odkodować format JSON wystarczy wykonać jego kod np. poprzez funkcję eval():

JavaScript:
  1. var myObject = eval(jsonData);

Po trzecie jak widać format jest zwięzły, czytelny i przez wielu uważany za bardziej naturalny niż np. XML.
Wszystkie te zalety sprawiają, że jest on bardzo często stosowany do wymiany danych nie tylko w modelu AJAX. Dla innych języków niż JS istnieją biblioteki do kodowania/dekodowania formatu JSON. Pełna ich lista znajduje się na stronie http://json.org/json-pl.html, na której można znaleźć także pełny opis tego formatu. Dla PHP istnieje nawet rozszerzenie json (wbudowane od wersji 5.2), dzięki czemu nie musimy korzystać z żadnych dodatkowych skryptów.

Format ten umożliwia przechowywanie dowolnych danych taki jak łańcuchy znaków, liczby, funkcje i całe obiekty wraz z właściwościami czy metodami dzięki czemu można bardzo wygodnie przesyłać dowolne dane pomiędzy np. skryptem PHP.odpowiadającym na żądanie funkcji JS. Warto pamiętać, iż ciągi znaków są przesyłane jako Unicode.

O ile odkodowanie danych z formatu JSON następuje poprzez funkcję eval() o tyle zakodowanie danych wymaga użycia dodatkowej funkcji, którą znaleźć można na stronie http://www.json.org/js.html. Osobiście nie jestem zadowolony z powyższego rozwiązania ponieważ polega ono na stworzeniu prototypu który "dokleja" się do danych po odkodowaniu dlatego polecam inne rozwiązanie czyli zwykłą funkcję (autor nieznany):

JavaScript:
  1. function toJsonString(o) {
  2.     var UNDEFINED
  3.     switch (typeof o) {
  4.         case 'string': return '"' + encodeJS(o) + '"'
  5.         case 'number': return String(o)
  6.         case 'object':
  7.             if(o) {
  8.                 var a = []
  9.                 if (o.constructor == Array) {
  10.                     for (var i = 0; i <o.length; i++) {
  11.                         var json = toJsonString(o[i])
  12.                         if(json != UNDEFINED) a[a.length] = json
  13.               }
  14.                     return '[' + a.join(',') + ']'
  15.                 } else if (o.constructor == Date) {
  16.                     return 'new Date(' + o.getTime() + ')'
  17.                 } else {
  18.                     for (var p in o) {
  19.                         var json = toJsonString(o[p])
  20.                         if (json != UNDEFINED) a[a.length] = (/^[A-Za-z_]\w*$/.test(p) ? ('"' + p + '":') : ('"' + encodeJS(p) + '":')) + json
  21.                     }
  22.                     return '{' + a.join(',') + '}'
  23.                 }
  24.             }
  25.             return 'null'
  26.         case 'boolean'  : return String(o)
  27.         case 'function' : return
  28.         case 'undefined': return 'null'
  29.     }
  30. }
  31. function encodeJS(s) {
  32.     return (!/[\x00-\x19\'\\]/.test(s)) ? s : s.replace(/([\\'])/g, '\\$1').replace(/\r/g, '\\r').replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/[\x00-\x19]/g, '')
  33. }

W PHP wykorzystując wbudowane bądź dodane rozszerzenie json można kodować/dekodować dane poprzez:

PHP:
  1. $data = json_decode($jsonData);
  2. $jsonData = json_encode($data);

Więcej o formacie JSON:
http://json.org/json-pl.html
http://pl.wikipedia.org/wiki/JSON
http://www.hunlock.com/blogs/Mastering_JSON_(_JavaScript_Object_Notation_)

Wzorzec factory należy do wzorców konstrukcyjnych. Pozwala na tworzenie obiektów bez konieczności specyfikacji klas na podstawie której będą tworzone. Umożliwia on stworzenie osobnej metody odpowiedzialnej za tworzenie nowych obiektów.

Aby pokazać działanie wzorca factory posłużę się prostym przykładem. Załóżmy, że mam kontroler, który w zależności od typu przekazanego pliku musi stworzyć nowy obiekt widoku i wywołać w nim metodę generującą widok. Zacznę od stworzenia interfejsu IView dla widoków:

PHP:
  1. interface IView
  2. {
  3.     function render();
  4. }

Następnie tworzę klasy dla widoków implementujące interfejs IView:

PHP:
  1. class HtmlView implements IView
  2. {
  3.     function render()
  4.     {
  5.         // generowanie widoku html
  6.         // [...]
  7.     }
  8. }
  9.  
  10. class XmlView implements IView
  11. {
  12.     function render()
  13.     {
  14.         // generowanie widoku xml
  15.         // [...]
  16.     }
  17. }

Pozostaje mi stworzenie klasy głównej:

PHP:
  1. class View
  2. {
  3.     static function factory($fileName)
  4.     {
  5.         switch(end(explode('.', $fileName)))
  6.         {
  7.             case 'html' :
  8.                 return new HtmlView();
  9.             case 'xml' :
  10.                 return new XmlView();
  11.             default :
  12.                 throw new Exception('Unknown file type');
  13.         }
  14.     }
  15. }

Metoda renderView() w zależności od rozszerzenia pliku przekazanego w parametrze zwraca obiekt odpowiedniej klasy. Na koniec pozostało jeszcze tylko uruchomienie metody renderView() klasy View:

PHP:
  1. $view = View::factory('index.html');
  2. $view->render();

Jak widać implementacja wzorca factory jest bardzo prosta i przydatna zarazem kiedy zachodzi potrzeba tworzenia obiektów bez specyfikacji klas.

Więcej o wzorcu factory:
http://pl.wikipedia.org/wiki/Wzorzec_metody_fabrykującej
http://www.fluffycat.com/PHP-Design-Patterns/Factory-Method
http://www.vincehuston.org/dp/factory_method.html
http://www.phppatterns.com/docs/design/the_factory_method

Wzorzec singleton należy do wzorców konstrukcyjnych. Służy on do ograniczania możliwości tworzenia obiektów danej klasy do jednej instancji oraz zapewniania globalnego punktu dostępu do niej. Wzorzec ten jest krytykowany ze względu na zbyt częste traktowanie go jako zamiennika dla zmiennych globalnych powszechnie uznawanych za niekorzystne.

Implementacja wzorca singleton:

PHP:
  1. class Singleton
  2. {
  3.     /**
  4.      * Obiekt instancji
  5.      *
  6.      * @var object
  7.      * @access private
  8.      * @static
  9.      */
  10.     static private $_instance;
  11.    
  12.     /**
  13.      * Konstruktor klasy
  14.      *
  15.      * @access private
  16.      */
  17.     private function __construct()  { }
  18.  
  19.     /**
  20.      * Metoda klonujaca
  21.      *
  22.      * @access private
  23.      */
  24.     private function __clone() { }
  25.    
  26.     /**
  27.      * Metoda zwraca instance obiektu
  28.      *
  29.      * @static
  30.      * @return object
  31.      */
  32.     static function getInstance()
  33.     {
  34.         if(!self::$_instance) {
  35.             self::$_instance = new self();
  36.         }
  37.         return self::$_instance;
  38.     }
  39.  
  40.     function foo()
  41.     {
  42.         // [...]
  43.     }
  44. }

Kluczowym elementem jest statyczna metoda getInstance(), która sprawdza istnienie prywatnej zmiennej statycznej $_instance. Jeśli zmienna ta nie istnieje wywoływany jest konstruktor klasy i do zmiennej jest przypisywany jej obiekt co zapobiega wielokrotnemu tworzeniu jej instancji. Jeśli obiekt klasy istnieje jest po prostu zwracany przez referencję. Dzięki temu, iż zarówno konstruktor jak i metoda __clone są prywatne nie ma możliwości ich wywołania spoza klasy co jest dodatkowym zabezpieczeniem przed próbą utworzenia obiektu bądź jego sklonowaniem.
Przykład wykorzystania:

PHP:
  1. Singleton::getInstance()->foo();

Najpierw pobieram instancję klasy Singleton a następnie wywołuję metodę foo().

Jak wspomniałem na początku wzorzec ten często uznawany jest za antywzorzec ponieważ bywa wykorzystywany jako zamienni dla zmiennych globalnych. Dlatego powinien być stosowanych tylko w określonych przypadkach głównie związanych z wydajnością np. pobieranie jednej instancji obiektu bazy danych ze względów na czas połączenia z bazą, oszczędność zasobów pamięci itp.

Więcej o wzorcu singleton:
http://pl.wikipedia.org/wiki/Wzorzec_singletonu
http://4programmers.net/PHP/Wzorce_Projektowe#id-Singleton
http://www.phppatterns.com/docs/design/singleton_pattern
http://www.fluffycat.com/PHP-Design-Patterns/Singleton
http://www.vincehuston.org/dp/singleton.html

Wzorzec decorator należy do wzorców strukturalnych. W praktyce umożliwia dynamiczne dodawanie nowych funkcji do istniejących klas bez ich fizycznej modyfikacji. Dzięki temu można rozszerzyć możliwości klasy bez ingerowania w jej kod pozostawiając jej oryginalną funkcjonalność.

Aby pokazać działanie wzorca decorator posłużę się prostym przykładem. Załóżmy, że mam klasę zapisującą dane do bazy. Nie chcę zmieniać jej kodu i funkcjonalności ale chcę ją rozszerzyć o walidację danych. Mógłbym zastosować dziedziczenie i wykorzystać dziedziczoną metodą do walidacji ale wówczas musiałbym zmodyfikować kod klasy głównej czego bardzo chcę uniknąć a dodatkowo każda zmiana klasy dziedziczącej wymuszałaby zmiany klas dziedziczonych.

Zacznę od stworzenia wspólnego interfejsu dla klasy dekorowanej i dekoratora:

PHP:
  1. interface IDecorator
  2. {
  3.     function save();
  4. }

Następnie stworzę klasę główną (dekorowaną) implementującą interfejs IDecorator, której kodu podczas rozszerzania nie mam zamiaru modyfikować:

PHP:
  1. class Decorable imlements IDecorator
  2. {
  3.     function save()
  4.     {
  5.         // zapis danych do bazy
  6.         // [...]
  7.     }
  8. }

Teraz przyszła kolej na stworzenie klasy dekorującej czyli wzbogacającej klasę główną Decorable o funkcję walidującą dane, która także implementuje interfejs IDecorator:

PHP:
  1. class Decorate implements IDecorator
  2. {
  3.     /**
  4.      * Obiekt klasy dekorowanej
  5.      *
  6.      * @var object
  7.      * @access private
  8.      */
  9.     private $_decorate;
  10.  
  11.     /**
  12.      * Konstruktor klasy
  13.      *
  14.      * @param object $decorable
  15.      */
  16.     function __construct(Decorable $decorable)
  17.     {
  18.         // przypisanie obiektu klasy dekorowanej do zmiennej prywatnej
  19.         $this->_decorable = $decorable
  20.     }
  21.  
  22.     /**
  23.      * Metoda uruchamia walidacje danych
  24.      */
  25.     function save()
  26.     {
  27.         // walidacja danych
  28.         // [...]
  29.  
  30.         // wywolanie oryginalnej metody z klasy dekorowanej
  31.         $this->_decorable->save();
  32.     }
  33. }

Do konstruktora klasy zostaje przekazany obiekt oryginalnej klasy dekorowanej Decorable. Na koniec pozostaje mi stworzenie obiektu klasy dekorowanej Decorable i przekazanie jej klasie dekorującej Decorate:

PHP:
  1. $action = new Decorate(new Decorable());
  2. $action->save();

Po stworzeniu obiektu klasy Decorable wywołuję metodę save(), która po przeprowadzeniu walidacji wywołuje metodę o tej samej nazwie klasy dekorowanej Decorable.

Jak więc widać rozszerzyłem funkcjonalność klasy oryginalnej nie dokonując w niej żadnych istotnych zmian. Podsumowując dekoratory są w pewnym sensie alternatywą dla dziedziczenia. Dziedziczenie rozszerza zachowanie klasy w trakcie kompilacji, w przeciwieństwie do dekoratorów, które rozszerzają klasy w czasie działania programu.

Więcej o wzorcu dekoratora:
http://pl.wikipedia.org/wiki/Wzorzec_dekoratora
http://4programmers.net/PHP/Wzorce_Projektowe#id-Dekorator
http://www.phppatterns.com/docs/design/decorator_pattern
http://www.fluffycat.com/PHP-Design-Patterns/Decorator
http://www.vincehuston.org/dp/decorator.html

Wzorzec observer należy do wzorców czynnościowych. W praktyce umożliwia on powiadamianie obiektów (obserwatorów) o zmianie danych obiektu czy klasy centralnej (obserwowanej) dając możliwość wielokrotnego wykorzystywania klas bez zbędnych modyfikacji ich kodu czyniąc go przy tym czytelniejszym i bardziej przejrzystym.

Aby pokazać działanie wzorca observer posłużę się prostym przykładem. Załóżmy, że mamy klasę modyfikującą dane w bazie i chcemy aby w momencie zapisu zmienionych danych został utworzony plik z cachem zawierającym nowe dane oraz aby informacja o tych zmianach trafiła do administratora.
Zacznę od stworzenia interfejsu dla obiektów obserwatorów, który zawierać będzie definicje metody update:

PHP:
  1. interface IObserver
  2. {
  3.     function update();
  4. }

Następnie stworzę 2 klasy obserwatorów implementujące powyższy interfejs, jedna odpowiedzialna będzie za utworzenie nowego cache'u a druga za powiadomienie admina o zmianach:

PHP:
  1. class CacheObserver implements IObserver
  2. {
  3.     /**
  4.      * Metoda zapisuje nowe dane do cache
  5.      */
  6.     function update()
  7.     {
  8.         // zapis danych do cache
  9.         // [...]
  10.     }
  11. }
  12.  
  13. class MailObserver implements IObserver
  14. {
  15.     /**
  16.      * Metoda wysyla maila do admina
  17.      */
  18.     function update()
  19.     {
  20.         // wyslanie maila do admina
  21.         // [...]
  22.     }
  23. }

Mając już obserwatorów utworzę klasę centralną (obserwowaną) czyli w naszym przykładzie modyfikującą dane osoby w bazie:

PHP:
  1. class ModifyObservable
  2. {
  3.     /**
  4.      * Tablica obserwatorow
  5.      *
  6.      * @var array
  7.      * @access private
  8.      */
  9.     private $_observers = array();
  10.  
  11.     /**
  12.      * Metoda dodaje obserwatora
  13.      *
  14.      * @param object Obiekt obserwatora
  15.      */
  16.     function addObserver($observer)
  17.     {
  18.         $this->_observers[] = $observer;
  19.     }
  20.    
  21.     /**
  22.      * Metoda powiadamia swoich obserwatorow o uaktualnieniu
  23.      */
  24.     function notify()
  25.     {
  26.         foreach($this->_observers as $observer) {
  27.             $observer->update();
  28.         }
  29.     }
  30.    
  31.     /**
  32.      * Metoda dokonuje modyfikacji danych
  33.      */
  34.     function update()
  35.     {
  36.         // modyfikacja danych
  37.         // [...]
  38.  
  39.         // powiadomienie obserwatorow
  40.         $this->notify();
  41.     }
  42. }

Metoda update() w klasie Modify aktualizuje dane oraz wywołuje metodę notify(), która to poprzez cykliczne wywołanie metod update() swoich obserwatorów (CacheObserver i MailObserver)

PHP:
  1. $modify = new ModifyObservable();
  2. $modify->addObserver(new CacheObserver());
  3. $modify->addObserver(new MailObserver());
  4. $modify->update();

Jak więc widać wzorzec ten jest dość prosty w implementacji i daje nam wymierne korzyści takie jak możliwość wielokrotnego wykorzystywania klas bez zbędnych modyfikacji kodu, unikanie trwałych i sztywnych zależności między klasami, czytelny i przejrzysty kod.

Więcej na temat wzorca observer:
http://pl.wikipedia.org/wiki/Wzorzec_obserwatora
http://4programmers.net/PHP/Wzorce_Projektowe#id-Obserwator
http://www.phppatterns.com/docs/design/observer_pattern
http://www.fluffycat.com/PHP-Design-Patterns/Observer/
http://www.vincehuston.org/dp/observer.html