Webcity.pl


  Stosy w PHP i ich wy...

  Instalacja bazy dany...

  Zdalna obsługa kompu...

  Serwer WAP i dynamic...

  Profesjonalni Webma(...

 

 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ł

Twój domowy serwer!

  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 |

Singleton w PHP

Autor: shw
   Wstęp
Kiedy mówimy o programowaniu obiektowym, coraz bardziej rozwijanym w PHP, mówimy o wielu kwestiach. Mądrzy ludzie piszą mądre książki o "obiektówce", a jednym z problemów poruszanych w tychże jest kontrola nad ilością utworzonych obiektów danej klasy.
Konkretnie problem tyczy się zabezpieczenia naszej klasy przed utworzeniem więcej niż jednego obiektu.

   Ale właściwie po co?
Powodów takiego postępowania może być wiele - chociażby np. zredukowanie niepotrzebnie alokowanej pamięci do minimum, wymiana danych z innej klasy bez czynienia tejże globalną i wiele innych z którymi programiści borykają się każdego dnia. Przykładem w PHP może być chociażby system wejścia-wyjścia, przy którym albo alokowalibyśmy dużo pamięci, tworząc obiekty w każdej potrzebnej klasie oddzielnie, albo chociażby uczylibyśmy się złych nawyków umieszczając globalny obiekt klasy (nie mówiąc o trudnych do wyśledzenia błędach spowodowanych chociażby zmianą nazwy).

   Rozwiazanie
Z problemem tym, zanim jeszcze pojawił się on w PHP, spotkali się programiści innych języków obiektowych i wymyślili rozwiązanie, które zostało zadaptowane do PHP - a nazywa się ono singleton.

Nazwa singleton wzięła się z matematycznej teorii mnogości i oznacza po prostu zbiór jednoelementowy. Zanim jednak o konkretnym kodzie, który okaże się bajecznie prosty, więcej o problemie.

   Kiedy to się przyda..
Skoro zaczęliśmy już o systemie wejścia-wyjścia. Część programistów, chociażby nauczonych doświadczeniem przejścia ze zmiennych superglobalnych w PHP3, na tablice globalne w PHP4 i wyżej (które również zmieniały nazwy) postanowiło implementować do swoich skryptów system wejścia-wyjścia, dzięki czemu skrypt był względnie odporny na wszelkie zmiany w tej kwestii w języku - wystarczyło po prostu przy jakichkolwiek zmianach zmienić odpowiednią klasę, zamiast zmieniać mnóstwo zmiennych w wielu plikach skryptu. Kiedy jednak przejdziemy w swoich skryptach na obiektówkę, pojawia się problem dostępu do niej w szeregu innych klas. Jednym z rozwiązań, jak pisałem, jest utworzenie "zmiennej globalnej" (czyli użycie w każdej klasie słowa global oraz nazwy tej zmiennej). Jednakże dobremu programiście rozwiązanie to nie będzie pasowało - a co się stanie, jeżeli ktoś zmieni nazwę tej zmiennej, albo ją nadpisze w dalszej części skryptu? Odnalezienie takiego błędu, gdy rozrośnie się on do szeregu plików i tysięcy linijek kodu, jest bardzo trudne (pomijając już nawet prawa Murphiego). Dlatego dobrze byłoby mieć możliwość posiadania "gdzieśtam" jednego, jedynego egzemplarza klasy, jak również i dostępu do niego z każdego miejsca w skrypcie. I tu z pomocą przychodzi koncepcja singleton.

   Pod względem programistycznym tworzy ona obiekt klasy tylko raz, a jeżeli takowy już istnieje - zwraca jedynie referencje do niego. Ale po kolei - kilka słów kluczowych dla osób, które się jeszcze z nimi nie spotkały.

   Troszkę teorii
static - za pomocą tego złowa tworzymy zmienną statyczną, która jako np. składowa klasy w C++ oznacza wspólną zmienną dla wszystkich obiektów danej klasy. Co to oznacza po chłopsku? Że jeżeli mamy dwa obiekty danej klasy i w jednym zmienimy wartość zmiennej statycznej, to w drugim będzie ona też zmieniona. Proste, prawda? Po prostu jeżeli potrzebujemy, aby coś było zmieniane dla wszystkich obiektów, deklarujemy to jako static.

referencja - zmienne w PHP można przekazywać dwojako: przez wartość lub przez referencję. Z pierwszym sposobem na pewno się już spokałeś, bo każde wywołanie zwykłej funkcji (dla ścisłości - w PHP4, ale o tym za chwilę) było przekazaniem przez wartość. Czyli wywołując funkcję ze zmienną jako parametrem przekazywaliśmy jej kopię (samo przekazanie jej jako argumentu nie zmieniało tej zmiennej).
   Jednakże można było przekazać jakąś zmienną przez referencję - czyli nie jako jej kopię, lecz odnośnik do niej, dzięki czemu można było operować wewnątrz funkcji na zmiennej z zewnątrz jednocześnie ją zmieniając. Tak samo można też zwracać dane.

Dla lepszego zrozumienia - kod:


<?php

// Funkcja "zwykla", czyli przekazujemy przez wartosc

function zwykla($var)
{

   $var = 100;

}

// Funkcja "niezwykla", czyli przekazujemy przez referencję

function referencja(&$var)
{

   $var = 200;

}

// Sprawdzamy dzialanie

$zmienna = 0;


zwykla($zmienna);

echo $zmienna; // Bez zmian - wartosc = 0

echo '<br />';

referencja($zmienna);

echo $zmienna; // Funkcja zmienila wartość zmiennej na 200

?>

Mam nadzieję, że teraz jest już wszystko jasne. I jak już pewnie zauważyłeś, referencje oznacza się przez znak ampersant, czyli "&". I jeszcze słowo wyjaśnienia odnośnie tego PHP4. Podany przykład jest tu poprawny w każdym przypadku niezależnie od tego, co byśmy przekazywali. Jednakże w PHP5 nastąpiła znacząca zmiana. Jeżeli argumentem funkcji (nawet naszej "zwykłej") jest obiekt jakiejś klasy - przekazywany jest on automatycznie jako referencja! Warto o tym pamiętać zawczasu. Tak więc, wywołując jakąkolwiek funkcję z parametrem będącym obiektem przekazujemy nie tylko jego wartość, ale i adres, przez co dajemy możliwość jego zmiany wewnątrz niej.

   Do rzeczy!
Ale rozpisałem się strasznie - przechodzimy zatem do singleton'u.

   Dla kompatybilności wstecz podam przykładowy kod zarówno dla PHP4, jak i PHP5, jednakże możliwość implementacji singletonu w PHP5 jest znacznie bardziej przyjazna i odpowiadająca innym językom - chociażby przez kontrolę dostępu.

Implementacja dla PHP4 wygląda następująco:


<?php
//plik: single_test.php

class test {

   var $zmienna;

   function &singleton() // Zwracamy referencje!!

   {

      static $instance; // Zmienna statyczna!!

   if(!isset($instance)) { // Tylko jezeli jeszcze nie ma obiektu

         $instance = new test;
      }
      return $instance;
   }
}

?>

I po kolei - tworzymy sobie klasę, w niej metodę singleton() (nazwa jest oczywiście dowolna, ale zwykle stosuje się właśnie ją), która zwraca referencję.
   W środku definiujemy zmienną statyczną (jak wyżej). Potem zwykłe sprawdzenie, czy została ona już zadeklarowana - jeżeli nie,tworzymy z niej nowy obiekt klasy. No i potem zwracamy. Atrybut $zmienna dodałem, żeby udowodnić wam w przykładzie wykorzystania, że to naprawdę działa :)
   A oto i przykład - czyli jak tego używać:


<?php
//plik: test.php

include('single_test.php'); // Includujemy powyzszy plik

$single1 =& test::singleton(); // Tworzymy 1 egzemplarz

$single1->zmienna = 100;

$single2 =& test::singleton(); // I drugi

echo $single2->zmienna; // Wydrukuje 100

?>

Na uwagę zasługują dwie kwestie: ponieważ metoda singleton() zwraca referencję, to musi być ona zapisana do zmiennej jako referencja - stąd "=&". Drugą kwestią jest wywołanie metody - nie tworzymy obiektu za pomocą new (również w PHP4 należy o tym pamiętać!), lecz przez przestrzeń nazw, czyli nazwę klasy, dwa dwukropki i nazwę metody - stąd test::singleton().

   A teraz wersja dla ludzi piszących już w PHP5, w którym programowanie obiektowe stoi na znacznie wyższym poziomie. Pierwsza dobra wiadomość: można zapomieć o referencjach, ponieważ przekazując obiekt przekazujemy referencję do niego, a singleton stosuje się tylko do obiektów.
   Druga rzecz - w PHP4 należy bezwględnie uważać z użyciem operatora new - o tyle jest to proste, jeżeli tylko my pracujemy na naszych klasach, a o tyle trudniejsze, jeżeli robią to inni, którym trzeba o tym przypominać. W PHP5 istnieje pewna sztuczka, która uniemożliwi użytkownikowi klasy na stworzenie obiektu za pomocą operatora new - z pomocą przychodzi kontrola dostępu.
   A oto i kod:


<?php
//plik single_test5_php5.php

class test5 {
   public $zmienna;

   protected __construct() {} // I oto nasza sztuczka

   public function singleton()
   {
      static $instance;
      if(!isset($instance)) {
         $instance = new test5;
      }
      return $instance;
   }
}

?>

Tak więc zniknęły "&" z wersji na PHP4 oraz doszła kontrola dostępu dla konstruktora (należy pamiętać, że w PHP5 funkcjonują obie wersje konstruktorów - zarówno nowe __construct(), jak i metoda o nazwie identycznej, jak klasa, są konstruktorami!). Z zewnątrz klasy jest on on niedostępny dzięki słowu protected, natomiast singleton() jest metodą tej klasy, a co za tym idzie - ma dostęp do innych metod oznaczonych jako protected.
   Dla pewności - test klasy:


<?php
//plik: test5.php

include('single_test5_php5.php'); // Includujemy powyzszy plik

$single1 = test5::singleton(); // Tworzymy 1 egzemplarz
$single1->zmienna = 500;
$single2 = test5::singleton(); // I drugi
echo $single2->zmienna; // Wydrukuje 500
// $single3 = new test5; // Wyrzuci blad (Fatal error) z braku dostepu do konstruktora
?>


   I krótki koniec
I to na tyle o singletonie w PHP. Zastosowań jest wiele i sami musicie je znaleźć (i zapewne tak własnie zrobicie).
Na koniec mała porada - żeby nie pisać za kazdym razem kodu typu nazwa_klasy::singleton(), spróbujcie napisać funkcję (u siebie nazwałem ją np. snew()), która będzie przyjmować nazwę klasy, a zwracać referencję do obiektu stworzonego za pomocą singletonu.

Powrót

 
 
Find jobs | WoW Gold | Wordpress Themes | Life Insurance | Home Insurance