-
Wstęp do programowania zorientowanego obiektowo w PHP5…
dodano 17.09.2008 / komentarzy: 1 / autor: m1chu
Piąta odsłona PHP w porównaniu z poprzednią jest w pełni funkcjonalnym, zorientowanym obiektowo językiem. Z fundamentalnego punktu widzenia OOP (skrót od Object Oriented Programming) jest koncepcją grupowania danych i kodu w logiczne całości zwane po prostu klasami. Tematyka ta wiąże się z takimi pojęciami jak deklaracja klasy, tworzenie instancji obiektu, metody, właściwości, kapsułkowanie, stałe klasy, czy metody i właściwości statyczne. I to właśnie te elementy będę starał się Wam łatwo, prosto i przyjemnie zaprezentować tym razem.
Deklaracja klasy, tworzenie, klonowanie oraz niszczenie instancji obiektu na przebudzenie…
Klasa jest reprezentacją metod (nazywanych także funkcjami) i właściwości (nazywanych także z nieobiektowych aplikacji, czy skryptów po prostu zmiennymi). Zbiór klas ma na celu stworzyć ogólny, współdziałający interfejs dla przyszłych użytkowników. Sama klasa w sobie, pomijając pewne zastosowania statyczne jest tylko kontenerem, projektem dla mniejszych paczek których jest reprezentacją. Użyć je można oczywiście poprzez utworzenie instancji na obiekcie, których można wykreować dowolnie dużo.
Pojęciem od którego zaczniemy jest deklaracja klasy, w najprostszej postaci wyglądająca tak:
<?php
class mojaKlasa {
// zawartosc klasy w postaci metod, wartosci czy stalych
}
?>Kiedy już wykonamy powyższą deklarację, możemy przystąpić do instancjonowania obiektu, które z goła jest tak samo proste jak poprzednia czynność.
$instancja = new mojaKlasa(); // za pomocą konstrukcji newPonieważ obiekt, w tym wypadku do zmiennej $instancja przekazywany jest zawsze jako uchwyt (w praktycznym podejściu można uważać, że jako referencja) możliwe jest bezproblemowe skopiowanie instancji do innej zmiennej poprzez ich zwyczajne przyrównanie. To rozróżnia zmienną $instancja od zwykłych zmiennych dla których dane przekazywane są jako wartość. Ważnym jest, że poprzez taki zabieg instancje odnoszą się do jednej klasy, więc zmiana danych poprzez jedną z nich automatycznie powoduje zmianę w drugiej. Można tego uniknąć poprzez klonowanie obiektu używając operatora clone (ponieważ dla nowej powielonej instancji zostanie zaalokowana nowa przestrzeń pamięci to zmiany na pierwotnej zmiennej przetrzymującej obiekt nie będę się odbijać na sklonowanej).
$instancja = new klasa();
$instancja->var = ‘X’;
$nowa_instancja = $instancja; // kopiowanie instancji, obydwie zmienne będą wskazywać na ten sam obiekt
$nowa_instancja->var = ‘Z’;echo $instancja->var; // zwroci Z
echo $nowa_instancja->var; // zwroci Z
[…]
$instancja = new klasa();
$instancja->var = ‘X’;
$sklonowana_instanca = clone $instancja; // klon instancji
$sklonowana_instancja = ‘Z’;echo $instancja->var; // zwroci X
echo $sklonowana_instancja->var // zwroci ZInstancja zostaje zniszczona automatycznie po wygenerowaniu całego skryptu. Nie mnie jednak gdybyśmy potrzebowali zrobić to ręcznie to służy do tego funkcja unset(parametr);.
Nie mniej jednak należy pamiętać, że jeśli w międzyczasie skopiujemy instancję tak jak to pokazałem powyżej to obiekt nie zostanie zniszczony dopóki nie usuniemy wszystkich zmiennych będących instancją danego obiektu.
Śniadanie z dziedziczeniem…
Żeby przejść do metod i właściwości niezbędne jest zapoznanie się z dziedziczeniami dostępnymi w OOP. Dziedziczenie pozwala na bezpośrednie korzystanie z zasobów jednej klasy przez inne, dodawanie nowych funkcji i zmiennych, a ostatecznie jeżeli nie ogranicza tego specjalny parametr metod lub klasy z której się dziedziczy także przedefiniowanie niektórych zasobów. A wszystko dzięki umieszczeniu w linii deklaracji klasy która ma dziedziczyć extends klasa_dziedziczona.
<?php
// w przykladzie pominieto typy hermetyzacji metod z racji tego, ze zostana one omowione w nastepnym dziale - przyjmijmy domyślnie więc, że są one publiczne, dostępne z każdego miejsca skryptu po utworzeniu instancjiclass klasaDziedziczona {
function metodaA()
{
print ‘wywolano -> klasaDziedziczona::metodaA’;
}
function metodaB()
{
print ‘wywolano -> klasaDziedziczona::metodaB’;
}
}class klasaDziedziczacaA extends klasaDziedziczona { // klasaDziedziczacaA dziedziczy z klasaDziedziczona
function metodaA()
{
print ‘wywolano -> klasaDziedziczacaA::metodaA’;
}
}class klasaDziedziczacaB extends klasaDziedziczona { // klasaDziedziczacaB dziedziczy z klasaDziedziczona
function metodaA()
{
print parent::metodaB();
}
function metodaB()
{
print ‘wywolano -> klasaDziedziczacaB::metodaA’;
}
function metodaX()
{
print ‘wywolano -> klasaDziedziczacaB::metodaX’;
}
}class klasaDziedziczacaC extends klasaDziedziczacaA { // klasaDziedziczacaC dziedziczy z klasaDziedziczacaA (zarazem może mieć dostęp do klasy bazowej klasaDziedziczona)
function metodaA()
{
print ‘wywolano -> klasaDziedziczacaC::metodaA’;
}
function metodaB()
{
print parent::metodaB();
}
function metodaC()
{
print klasaDziedziczona::metodaB();
}
function metodaD()
{
print klasaDziedziczacaB::metodaX();
}
}$klasa = new klasaDziedziczona();
$klasaA = new klasaDziedziczacaA();
$klasaB = new klasaDziedziczacaB();
$klasaC = new klasaDziedziczacaC();$klasa->metodaA(); // zwroci wywolano -> klasaDziedziczona::metodaA
$klasa->metodaB(); // zwroci wywolano -> klasaDziedziczona::metodaB
$klasaA->metodaA(); // zwroci wywolano -> klasaDziedziczacaA::metodaA
$klasaB->metodaA(); // zwroci wywolano -> klasaDziedziczona::metodaB
$klasaB->metodaB(); // zwroci wywolano -> klasaDziedziczacaB::metodaB
$klasaC->metodaA(); // zwroci wywolano -> klasaDziedziczacaC::metodaA
$klasaC->metodaB(); // zwroci wywolano -> klasaDziedziczona::metodaB
$klasaC->metodaC(); // zwroci wywolano -> klasaDziedziczona::metodaB
$klasaC->metodaD(); // zwroci wywolano -> klasaDziedziczacaB::metodaX
?>Kilka słów wyjaśnienia. Z klasy nadrzędnej dziedziczą bezpośrednio dwie kolejne: klasaDziedziczacaA i klasaDziedziczacaB. W pierwszej z nich występuje metoda nadpisująca metodę z klasy dziedziczonej (prościej mówiąc, o tej samej nazwie), przez co wywołanie $klasaA->metodaA(); powoduje, że otrzymujemy treść z klasy dziedziczącej, a nie dziedziczonej. W drugiej z tych klas miałem zamiar w metodzie metodaA() pokazać użycie operatora zasięgu :: i słowa parent. Pozwala ono nam na dostęp do nadpisanych metod w klasie z której dziedziczymy (a w wypadku ciągu klas dziedziczonych po sobie z najwyższego rodzica). W tym wypadku jest to nam potrzebne, gdyż nadpisanie następuje właśnie w klasie w której się znajdujemy w metodzie metodaB(). No i ostatecznie w klasie klasaDziedziczacaC jest pokazane jak odnieść się do metody rodzica z poziomu któregoś dziedziczenia z rzędu, a także jak statycznie wywołać metody które znajdują się w klasie rodzica lub w klasach pośredniczących.
Ktoś mógłby teraz spytać dlaczego nie użyłem wielokrotnego dziedziczenia. Takowe występuje tylko w przypadku interfejsów, o czym wspomnę za pewnie w następnej części artykułu. Oczywiście dałoby się to pośrednio za pomocą dostępnych w PHP narzędzi ominąć, ale to już temat na osobny wpis z omówieniem takowej metody.
Jest także jeszcze jedna metodyka korzystania z dziedziczenia. Polega ona na tworzeniu instancji tylko obiektu klasy dziedziczącej.
<?php
// w przykladzie pominieto typy hermetyzacji metod z racji tego, ze zostana one omowione w nastepnym dziale - przyjmijmy domyślnie więc, że są one publiczne, dostępne z każdego miejsca skryptu po utworzeniu instancjiclass klasaDziedziczona {
function metodaA()
{
print ‘wywolano -> klasaDziedziczona::metodaA’;
}
function metodaX()
{
print ‘wywolano -> klasaDziedziczona::metodaX’;
}
}class klasaDziedziczaca extends klasaDziedziczona {
function metodaA()
{
print ‘wywolano -> klasaDziedziczaca::metodaA’;
}
function metodaB()
{
print parent::metodaA();
}
}$instancja = new klasaDziedziczaca();
$instancja->metodaA(); // zwroci wywolano -> klasaDziedziczaca::metodaA
$instancja->metodaB(); // zwroci wywolano -> klasaDziedziczona::metodaA
$instancja->metodaX(); // zwroci wywolano -> klasaDziedziczona::metodaX
?>Jak widać na ostatnim użyciu metody bez problemu można korzystać z nieprzedefiniowanych danych klasy bazowej. Należy także wiedzieć, że metody magiczne (o których będzie poniżej) takie jak __construct wyszukiwane są od najniższej klasy dziedziczącej, aż do napotkania pierwszej metody danego typu. Przykładowa, wymieniona przed chwilą metoda konstrukcji wykonywana jest w klasie bazowej jedynie, jeżeli nie znajduje się w żadnej z potomnych jej klas. Można je podpiąć więc pod zasadę nadpisywania, inaczej przedefiniowania. Więcej o tym będzie poniżej.
Na deser zasady działania metod i właściwości…
Na początek wypadałoby poruszyć temat wspomnianego kapsułkowania lub bardziej z angielskiego - enkapsulacji. Polega ona na pewnym ukryciu danych w postaci zmiennych klasy, bądź jej funkcji w taki sposób, aby były one widoczne tylko i wyłącznie w funkcjach zaprzyjaźnionych, klasach dziedziczących lub metodach tej samej klasy (występuje wtedy tzw. pełna hermetyzacja). Z poniższych czterech typów pierwsze trzy mogą, lecz nie muszą łączyć się z czwartą w pary (tworząc np. metody chronione-finalne).

Gdybyśmy mieli umieścić pustą, przykładową metodę wewnątrz w.w. klasy to wyglądałaby ona np. tak:
<?php
class mojaKlasa {
public function wyswietlWartosc() // metoda publiczna dostępna z każdego miejsca
{
return 1;
}
}
?>Jak można zauważyć tworzenie metod wygląda praktycznie jak tworzenie zwykłych funkcji (wraz z możliwością sparametryzowania metod), z tymże przed function dodajemy typ metody. Do metod wewnątrz klasy lub z klas potomnych odnosimy się z specjalnej właściwości wskazującej zawsze na obiekt nazwanej $this.
<?php
class resultClass {
public function publicFunction($data) // metoda publiczna
{
print ‘Parametr: ‘ . $data;
}
private function privateFunction($data) // metoda prywatna dostępna tylko z tej klasy
{
print ‘Parametr: ‘ . $data;
}
protected function protectedFunction($data) // metoda chroniona dostępna z tej klasy i klas dziedziczących
{
print ‘Parametr: ‘ . $data;
}
final public function finalFunction($data) // publiczna metoda finalna (może być też protected) niemogąca być przedefiniowana w klasach potomnych
{
print ‘Parametr: ‘ . $data;
}
public function tryFromInternalPartOfClass($data) // klasa publiczna obrazująca wywołanie różnych typów metod z innej metody tej klasy
{
$this->publicFunction($data); // zadziała
$this->privateFunction($data); // zadziała
$this->protectedFunction($data); // zadziała
$this->finalFunction($data); // zadziała
}
}class callClass extends resultClass {
// utworzone w celu sprawdzenia wyniku odwolania sie do metod roznego typu w klasie bazowej
public function callPrivateFunction($data)
{
$this->privateFunction($data);
}
public function callPublicFunction($data)
{
$this->publicFunction($data);
}
public function callProtectedFunction($data)
{
$this->protectedFunction($data);
}
public function finalFunction($data) // proba przedefiniowania metody finalnej klasy bazowej
{
$this->finalFunction($data);
}
}$tekst = ‘argv’; // tekst do wypisania
$obj = new callClass(); // obiekt klasy potomnej
$obj->callPrivateFunction($tekst); // zwroci blad, albo zatrzyma skrypt z powodu proby wywolania metody prywatnej z klasy dziedziczonej
$obj->callPublicFunction($tekst); // zwroci Parametr: argv
$obj->callProtectedFunction($tekst); // zwroci Parametr: argv
$obj->finalFunction($tekst); // zwroci blad, albo zatrzyma dzialanie skryptu z powodu proby nadpisania metody finalnej z klasy bazowej
unset($obj);$obj = new resultClass(); // obiekt wczesniejszej klasy bazowej
$obj->publicFunction($tekst); // zwroci Parametr: argv
$obj->finalFunction($tekst); // zwroci Parametr: argv, poniewaz pomimo ze metoda jest finalna to jest takze typu publicznego
$obj->privateFunction($tekst); // zwroci blad, albo zatrzyma dzialanie skryptu
$obj->protectedFunction($tekst); // zwroci blad, albo zatrzyma dzialanie skryptu poniewaz z zewnatrz klasy bazowej probujemy wywolac metode chroniona$obj->tryFromInternalPartOfClass($data); // odwola sie prawidlowo do kazdej z metod wewnatrz tej wywolywanej
?>Adekwatnie sprawa miewa się z zmiennymi klasy. Wystarczy przed ich nazwą dodać jeden z pierwszych trzech typów.
<?php
class data {
public $data; // własciwosc dostepna publicznie
private $dzien; // własciwosc dostepna tylko w klasie data
protected $czas; // własciwosc dostepna w klasie data i czas
public function pokazDate()
{
print $this->data;
}
}class czas extends data {
public function pokazCzas()
{
print $this->czas[0];
}
public function pokazDzien()
{
print $this->dzien;
}
public function ustawCzas($czas)
{
if ( !isset($this->czas) )
{
$this->czas = $czas;
}
}
}$obj = new czas(); // obiekt klasy potomnej
$obj->data = ‘10.10.2000′; // zadziala, poniewaz zmienna obiektu klasy jest publiczna
$obj->czas = array(‘10′, ‘10′, ‘10′); // nie zadziala, zostanie wywolany blad lub zatrzymanie skryptu gdyz zmienna jest typu chronionego
$obj->data = ‘niedziela’; // nie zadziała, zostanie wywolany blad lub zatrzymanie skryptu gdyz zmienna jest typu prywatnego$obj->pokazDate(); // zostanie wyswietlona data ustawiona w $obj->data
$obj->ustawCzas(array(‘10′, ‘10′, ‘10′)); // ustawi czas w postaci tablicy przekazanej w parametrze ponieważ metoda w klasie dziedziczącej będzie przypisywać tablicę do właściwości chronionej klasy bazowej
$obj->pokazCzas(); // zostanie wyswietlona godzina = 10 (pierwszy element tablicy parametru) o ile zostanie wcześniej wywołana funkcja klasy w postaci $obj->ustawCzas(param)
$obj->pokazDzien(); // nie zostanie wyswietlone nic, gdyz do właściwości $this->dzien nie przekazano nic z racji niemożności zrobienia tego z zewnątrz klasy
?>Warto byłoby dodać, że zerować, bądź po prostu narzucać wartość właściwością można z trzech poziomów. Z miejsca deklaracji, z konstruktora (o którym poniżej), a także z wnętrza uprawnionych do tego metod.
No i na koniec przykład działania wspomnianego przeze mnie użycia final z klasą:
<?php
final class klasaBazowa { // klasa finalna
public function test() // uzywanie w takim przypadku final przed typem metody jest niepotrzebne
{
print ‘wywolano -> klasaBazowa::test’;
}
}class klasaPotomna extends klasaBazowa {}; // zakonczy sie bledem krytycznym poniewaz nie mozna dziedziczyc po klasie finalnej
?>Lunch z metodami, właściwościami statycznymi i stałymi…
O definiowaniu stałych w zakresie ogólnym PHP już pisałem. Przybliżę jednak samą kwestię ich użycia w klasach, gdyż tam jest to niewystarczająco poruszone.
Stałe klasy tworzymy poprzez użycie zwrotu const. Stałe mogą być deklarowane w klasach (w tym w finalnych) i interfejsach. Nie mogą być przedefiniowane. Ich wartość musi być stałym wyrażeniem (np. ciągiem znaków, liczbą, itp.). Nie może być za to wartością zmiennej, czy rezultatem operacji matematycznej. Z reguły dla zachowania dobrych nawyków przyjmuje się, że nazwę stałej zapisuje się drukowanymi znakami.
const NAZWA_STALEJ = ‘wartosc’;Do stałej domyślnie w klasie odnosimy się poprzez słowo self i operator zasięgu ::. Pod względem użytkowania sprawa miewa się adekwatnie jak w przypadku opisywanego wyżej parent::. Funkcjonalnie self:: daje dostęp do metod i pól statycznych w danej klasie. Takowym, uogólniając jest stała. W klasach potomnych odniesienie do stałej w klasie bazowej odbywa się tak samo, ale za pomocą wspomnianego już parent::.
Z poza klasy mając wersję PHP niższą niż 5.3 możemy operować na tego typu zasobach poprzez operator statyczności lub poprzez wskaźnik obiektu na opcjonalną metodę zwracającą wartość stałej. W wersji w.w. można odwołać się bezpośrednio poprzez obiekt klasy bądź statycznie poprzez przypisaną do zmiennej nazwę klasy.
<?php
final class klasaFinalna {
const FIN = ‘final done’;public function pobierzStala()
{
print self::FIN;
}
}class klasaBazowa {
const PRE = ‘normal done’;
const DEF = ‘normal done’;
public function pobierzStalaBazowa()
{
return self::DEF;
}
}class klasaPochodna extends klasaBazowa {
const PRE = ‘freakin failed’;
public function pobierzStalaZKlasyBazowej()
{
return parent::DEF;
}
}$obj = new klasaPochodna();
$obj_f = new klasaFinalna();print $obj->pobierzStalaBazowa(); // zwroci normal done
$obj_f->pobierzStala(); // zwroci final done poniewaz zwyczajnie w klasie finalnej tez mozna w skrypcie uzywac stalych
print klasaPochodna::PRE; // nie zwroci nic i zakonczy sie bledem lub zatrzymaniem skryptu z racji proby w klasie pochodnej nadpisania stalej z klasy bazowej - co jest niedozwolone
print $obj->pobierzStalaZKlasyBazowej(); // zwroci normal done jako przyklad uzycia stalej z klasy bazowej w klasie dziedziczacej
?>Dlaczego powinno używać się stałych klasowych, a nie zwykłych definiowanych poprzez funkcję define(params);? Z dwóch powodów. Estetycznego - systematyzują kod. I co ważniejsze - optymalnego, gdyż działają szybciej niż te pierwotne.
Co do statyczności w PHP5 jest ona przestrzegana bardziej restrykcyjnie. Nie można już wywoływać każdej metody, czy właściwości statycznie. Trzeba przed nazwą funkcji klasy i function dodać static, podobnie jest w wypadku zmiennych z tymże przed ich nazwą. W metodach statycznych można używać tylko statycznych pól, a przy odwoływaniu się do zasobów statycznych nie należy robić tego w postaci notacji obiektowej. Elementy tego typu podlegają także zasadą kapsułkowania. Pola za to nie wymagają tworzenia instancji obiektu. Wystarczy posłużyć się nazwą klasy w skrypcie, a jak już wspomniałem w bazowej i dziedziczonych klasach odpowiednio są to self:: i parent::.
<?php
class klasa {
public static $czas;
private static $miasto;
public static function zaladujDane()
{
self::$czas = date(‘H:i’, time());
return self::$czas;
}
public function zaladujMiasto($miasto)
{
self::$miasto = $miasto;
return self::$miasto;
}
}print ‘Godzina: ‘ . klasa::zaladujDane(); // zwroci Godzina: GG:MM (godzine wraz z minutami)
$instancja = new klasa();
print ‘Miasto: ‘ . $instancja->zaladujMiasto(‘Londyn’); // zwroci Miasto: Londyn, gdyz dostep do wlasciowsci statycznej odbywa sie w metodzie z wnetrza klasy
?>Reasumując podstawową zaletą jest fakt, że nie potrzeba tworzyć instancji w celu skorzystania z statycznych zasobów (elementy w stylu $instancja->, czy $this-> nie zadziałają). Przydaję się to w wielu różnych, bardziej zaawansowanych zastosowaniach, np. przy tworzeniu singletonu, o czym w następnej części kursu.
Co dziś dobrego na obiad? Konstruktory i destruktory…
Zasada działania konstruktora i destruktora klasy jest bardzo prosta. Są to dwie wbudowane w PHP5 metody wywoływane automatycznie, pierwsza po utworzeniu obiektu, a druga po jego zniszczeniu (po załadowaniu strony bądź poprzez użycie unset($var);). Co za tym idzie żadna z nich nie jest wywoływana przy użyciu statycznego odwołania i bez wykreowania instancji obiektu.
Konstruktor tworzymy poprzez nadanie metodzie nazwy __construct(params), a destruktor __destruct(). Możemy, lecz w tym wypadku nie jesteśmy do tego koniecznie zobligowani nadać tym metodom typ (np. publiczny).
Do czego mogą się przydać te dwie funkcje? Wszystko zależy od potrzeb, ale mogą np. do zerowania pól, otwierania, zamykania różnego rodzaju połączeń, czy tworzenia lub niszczenia innych obiektów.
<?php
final class klasa {
private static $bin;
public function __construct($bin)
{
self::$bin = (int)$bin; // nadanie domyslnych wartosci przy utworzeniu obiektu
}
public function __destruct()
{
self::$bin = 0;
}
}$instancja = new klasa(1); // wywolanie __construct i wykonanie jej zawartosci
// w tym miejscu (na koncu skryptu) automatycznie wywolywane jest __destruct
?>Ciąg dalszy metod magicznych na kolacje…
Jest pewien zbiór metod wbudowanych w OOP piątej wersji PHP, w tym __construct() i __destruct(), które są predefiniowane do specyficznego użycia i nie można ich nazewnictwa powielać w klasach (dokumentacja zaleca także, aby przy tworzeniu metod nie rozpoczynać ich nazwy od __, gdyż w przyszłości może pojawić się więcej opisywanych właśnie zasobów rozpoczynających się od takiego ciągu).
<?php
final class magiczneMetody {
private $user_id;
private $fn;
private $mode;
private $handle;
public $temp1;
public $temp2;
public function __construct($filename, $mode)
{
$this->user_id = array(
‘name’ => ‘vivee’
);
$this->fn = $filename;
$this->mode = $mode;
$this->handle = fopen($this->fn, $this->mode);
}
public function __destruct()
{
fclose($this->handle);
}
public function __sleep()
{
$this->user_id[‘name’] = ‘m1chu’;
return array(‘user_id’); // zwracamy tablice zmiennych do ponownego zaladowania po deserializacji
}
public function __wakeup()
{
$this->user_id[’stat’] = ‘working…’;
}
public function __call($name, $params)
{
print ‘Wywołano nieistniejącą metodę ‘ . $name . ‘ o parametrach: ‘;
if ( $params[0] != ” )
{
$counted_params = count($params);
for ( $i = 0; $i < $counted_params; ++$i )
{
print ( $i > 0 ? ‘, ‘ . $params[$i] : $params[$i] );
}
}
else {
print ‘brak’;
}
}
public function __clone()
{
$this->handle = fopen($this->fn, $this->mode);
}
public function __get($pole)
{
print ‘Wywołano nieistniejące pole: ‘ . $pole;
}
public function __set($name, $value)
{
mysql_query(‘INSERT INTO logs (log_name, log_val) VALUES(\’‘ . $name . ‘\’, \’‘ . $value . ‘\’‘);
print ‘Próbowano przypisać do nieistniejącej właściwości ‘ . $name . ‘ wartość ‘ . $value;
}
public function __isset($var)
{
print ‘Zmienna ‘ . $var . ‘ nie została ustawiona’;
}
public function __toString()
{
print ‘Nie ma dostepu do obiektu :D’;
}
public static function __set_state($array)
{
$temp_obj = new magiczneMetody();
$temp_obj->temp1 = $array[‘temp1′];
$temp_obj->temp2 = $array[‘temp2′];
return $temp_obj;
}
}function __autoload($class)
{
require ‘./klasa.php’;
}$obiekt = new magiczneMetody(‘file.txt’, ‘r+’);
// zasada dzialania __sleep() i __wakeup()
print_r($obiekt); // zwroci: magiczneMetody Object ( [user_id:private] => Array ( [name] => vivee ) )
$serialized = serialize($obiekt); // wywolanie przed serializacja metody magicznej __sleep()
print_r(unserialize($serialized)); // zwroci: magiczneMetody Object ( [user_id:private] => Array ( [name] => m1chu [stat] => working… ) )// zasada dzialania __call()
$obiekt->bezParametru(); // nieistniejaca metoda, zwroci: Wywołano nieistniejącą metodę bezParametru o parametrach: brak
$obiekt->zParametrami(1, true, ’string’); // nieistniejaca metoda, zwroci: Wywołano nieistniejącą metodę zParametrami o parametrach: 1, 1, string// zasada dzialania __clone()
$clone = clone $obiekt; // sklonowanie obiektu wraz z wywolaniem nowego strumienia do zasobu// zasada dzialania __get()
print $obiekt->nieistniejacePole; // nie istnieje taka własciwosc w klasie, zostanie wywolana metoda __get(param)// zasada dzialania __set()
// polaczenie z baza danych (dla przykladu MySQL)
$obiekt->username = ‘vivee’; // nie istnieje taka wlasciowsc w klasie, a poniewaz staramy sie do niej cos przypisac to zostanie wywolana metoda __set(params)
// koniec polaczenia z baza danych// zasada dzialania __isset()
isset($obiekt->username); // zwroci Zmienna username nie została ustawiona// zasada dzialania __toString()
print $obiekt; // zrzutowanie na ciag znakow obiektu wiec zostanie wywolane __toString()// zasada dzialania __set_state()
$obiekt->temp1 = ‘test’;
$obiekt->temp2 = ‘test drugi’;
$obiekt2 = var_export($obiekt, true);
var_dump($obiekt2); // wyswietli string(206) "magiczneMetody::__set_state(array( ‘user_id’ => array ( ‘name’ => ‘vivee’, ), ‘fn’ => ‘file.txt’, ‘mode’ => ‘r+’, ‘handle’ => false, ‘temp1′ => ‘test’, ‘temp2′ => ‘test drugi’, ))"// zasada dzialania funkcji __autoload()
$nieistniejaca_klasa = new jakasKlasa(); // nastepuje proba stworzenia instancji niedostepnej klasy - PHP poprzez __autoload() postara sie zaincludowac plik z klasa i ponownie utworzyc obiekt
$nieistniejaca_klasa->istniejacaMetoda(); // jesli uda sie utworzyc obiekt zostanie wywolana nastepujaca metoda
?>Do poduszki - metodyka postępowania wstępnego…
Dziwnie to wygląda, ale na koniec wypadałoby napisać kilka zdań o tym jak w ogóle podejść do programowania obiektowego. Bo pisanie klas to nie tylko bezmyślne trzepanie kodu w postaci metod tak, żeby później można to było z marszu i masowo użyć poprzez instancję obiektu klasy.
Jeśli pracujesz nad dużym projektem, to prawdopodobnie wiesz co robić. Dokumentacja i od cholery konstruktywnych komentarzy w kodzie. Pomimo, że OOP w przypadku podziału pracy na kilka osób ma na celu ułatwienie pracy w taki sposób, aby nie musiało się przeglądać całego kodu napisanego przez współtowarzysza a jedynie skorzystać z stworzonych przez niego metod i pól to niekiedy nie można zrobić czegoś inaczej niż modyfikując kod współpracownika.
W mniejszych projektach, szczególnie tych gdzie programuje tylko jedna osoba jestem za tym, żeby nie marnować niepotrzebnie kartek papieru i próbować tworzyć układając plan w głowie. Wystarczy przecież logicznie myśleć. Wiem, że dla niektórych wydaje się to abstrakcyjne. Dla mnie też było, gdy zaczynałem. Musicie po prostu napisać kilka skryptów, kilka tysięcy linijek kodu i zrozumiecie o co chodzi. Podstawą jest wyrobienie sobie swojego stylu pisania na podstawie aktualnych dogmatów tworzenia kodu. Pamiętajcie, że zarówno w obiektowym programowaniu w PHP, jak i zresztą w każdej dziedzinie życia sucha i niekiedy bezsensowna teoria nigdy nie nauczy Was tyle co własna praktyka. Może jedynie być informacyjnym preludium do Waszej dalszej, indywidualnej nauki, czy pracy…
Mam nadzieję, że wybaczycie mi trochę powtórzeń (i zarazem wszelkie pomyłki), niestety w większości były niezbędne do opisu poruszanej problematyki. Niedługo kolejna część o programowaniu zorientowanym obiektowo.
copyright © 2008, m1chu
udostępnione na licencji CC dla vivee.info i m1chu.eu












Komentarze / dodaj komentarz
autor: Flacktub
dodano: 17.09.2008
Przyda się ! :]
Napisz komentarz