dodatek_b.pdf

(205 KB) Pobierz
Oto przyk³ady stylów nag³ówków:
Dodatek B
PHP i programowanie zorientowane obiektowo
W niniejszym dodatku zapoznamy się z nieco bardziej zaawansowanymi technikami programistycznymi niż te,
którymi zajmowaliśmy się dotychczas. Głównym obszarem naszych zainteresowań będzie programowanie
zorientowane obiektowo, ale oprócz niego omówimy także kilka interesujących funkcji i technik.
Miejmy nadzieję, że treść niniejszego dodatku wyzwoli w nas własne pomysły i zamiast wnikać zbyt głęboko w
tematykę, powinien zachęcić nas do zdobycia głębszej wiedzy na temat obiektowości w PHP.
Na końcu dodatku, utworzymy bardzo prosty, zorientowany obiektowo system obsługi koszyków zakupowych.
OOPs!
W ramach wstępu, należy powiedzieć, że programowanie zorientowane obiektowo (ang. OOP — Object-
Oriented Programming) zastosowano po raz pierwszy w latach sześćdziesiątych, w języku Simula. Od tamtego
czasu, powstało wiele bardziej lub mniej zorientowanych obiektowo języków programowania i obecnie
większość komercyjnych języków, takie jak Java, C++ czy Visual Basic, bazują na zasadach OOP
Czym jednak jest programowanie zorientowane obiektowo?
No cóż, w każdym programie występują zmienne, przechowujące dane oraz funkcje wykonujące operacje
określonych typów i korzystające z tychże zmiennych. W programowaniu tradycyjnym, owe zmienne i funkcje
występują jako oddzielne elementy. W programowaniu obiektowym zaś, zmienne są grupowane z funkcjami w
odrębnych modułach, zwanych klasami.
Klasa składa się z dowolnej liczby właściwości (danych) i metod (funkcji). Po zdefiniowaniu klasy możemy
utworzyć dowolną liczbę należących do niej obiektów, w podobny sposób, w jaki tworzymy dowolne liczby
zmiennych, zawierających dane typu integer.
PHP sam w sobie nie jest językiem zorientowanym obiektowo, ale ponieważ zezwala na obiektowy styl
programowania, za taki go uznajemy.
OOP w przykładzie
Programowanie w języku obiektowym można postrzegać w sposób podobny do tego, w jaki obserwujemy świat
wokół nas. Jesteśmy otoczeni osobnymi obiektami, z którymi codziennie nawiązujemy interakcję.
Takim obiektem jest komputer, samochód, telewizor, a nawet kolega w pubie. Wszystkie obiekty dysponują
właściwościami i funkcjami, które mogą wykonywać, czasem na nasze żądanie, a czasem samorzutnie. Silnik
samochodu uruchamia się, gdy włączamy zapłon, komputer wczytuje program, a kolega traci równowagę, gdy
postawimy mu zbyt wiele drinków.
Ważne jest to, że nie musimy znać złożonych zagadnień wewnętrznego funkcjonowania tych obiektów. Nie
musimy być mechanikami samochodowymi, by umieć uruchomić samochód, nie musimy być programistami, by
móc pracować z użyciem komputera, ani nawet nie musimy znać się na biologii, by przewidzieć ile piw musi
wypić kolega, by stracić równowagę.
Podobna koncepcja rządzi programowaniem zorientowanym obiektowo, a żeby zrozumieć ją głębiej, posłużymy
się przykładem teoretycznym, w którym główną rolę odegra telewizor.
Właściwości
Jeśli przyjrzymy się telewizorowi, poza różnymi interesującymi cechami, widocznymi w niektórych modelach,
znajdziemy zestaw kilku właściwości ogólnych. Wymieńmy kilka z nich:
Marka — producent telewizora.
Kanał — stacja, której program jest aktualnie wyświetlany przez telewizor.
1
Głośność — poziom dźwięku wydobywającego się z telewizora.
Stan (włączony/wyłączony) — czy telewizor w danym momencie pracuje, czy też nie.
W programowaniu obiektowym, cechy te nazwalibyśmy właściwościami klasy Television. Składnia deklaracji w
PHP wygląda następująco:
<?
class Television {
var $make;
var $channel;
var $volume;
}
?>
Aby korzystać z klas w skryptach PHP, należy je najpierw zdefiniować i wymienić wszystkie ich właściwości
oraz metody.
A zatem, zdefiniowaliśmy właśnie właściwości klasy Television, ale jak jej użyć? No cóż, odpowiedź brzmi tak,
że nie da się spożytkować klasy dopóki nie zdefiniujemy jej metod.
Metody
Zastanówmy się nad funkcjami, które może wykonać w naszym telewizorze:
Zmienić kanał
Zwiększyć poziom dźwięku
Zmniejszyć poziom dźwięku
Włączyć odbiornik lub go wyłączyć.
W przypadku każdego telewizora, opcje te są udostępniane za pomocą pilota, a zmiany kanału dokonuje się
poprzez naciśnięcie przycisku.
Jeśli jednak przyjrzymy się zapisanemu wyżej kodowi, zauważymy, ze jedną z właściwości Television jest make
(marka) i żaden ze znanych mi telewizorów nie dysponuje przyciskiem powodującym zmianę marki! Tylko
niektóre właściwości obiektu mogą być modyfikowane, podczas gdy inne pozostają stałe.
Jeśli więc dodamy owe metody do definicji klasy Television, otrzymamy następujący kod:
<?
class Television {
// Class properties
var $volume;
var $channel;
var $make;
// Constructor
function Television ($theMake) {
$make = $theMake;
}
// Class methods
function increaseVolume() {
//Add one to the current volume
$this->volume++;
}
function decreaseVolume() {
//Subtract one from the current volume
$this->volume--;
}
function setChannel($newChannel) {
//Set channel to newChannel
$this->channel = $newChannel;
}
2
function getChannel() {
//Just return the current channel
return $channel;
}
}
?>
Jak widać, definiowanie metod dla określonej klasy przebiega w ten sam sposób, jak definiowanie dowolnych
funkcji w PHP. Korzystamy ze słowa kluczowego function, deklarując funkcję wewnątrz pary klamer.
Prawdopodobnie każdy zauważył także, że deklaracje funkcji pojawiają się wewnątrz definicji klasy —
wewnątrz jej klamer. Jest to bardzo ważne, gdyż metody zdefiniowane poza klasą nie będą działały!
W pierwszej metodzie, increaseVolume próbujemy zwiększyć bieżącą wartość głośności o jeden. Wywołujemy
w tym celu operator ++, z którego korzystaliśmy także w poprzednich rozdziałach, choć może nam nie być
znany termin $this.
$this jest zmienną specjalną, która odwołuje się do bieżącej instancji klasy. Każda kopia obiektu Television ma
własny zestaw zmiennych, które nie są współdzielone z innymi obiektami Television. Słowo kluczowe $this
świadczy o naszym zainteresowaniu tylko obiektem bieżącym.
Innym elementem notacyjnym, który może być nam obcy, jest operator "->". W PHP służy on nam do
uzyskiwania dostępu do właściwości i metod obiektów. A więc, w naszym przykładzie, poprzez zapis $this-
>channel odwołujemy się do zmiennej channel bieżącego obiektu Television.
Pozostałe funkcje są bardzo podobne, a zamiany wartości ich zmiennych przynoszą odpowiednie skutki, czego
można się domyślić — decreaseVolume odejmuje jedność od bieżącej głośności, setChannel ustawia wartość
właściwości $channel, natomiast getChannel zwraca wartość bieżącego kanału.
Jest to koncepcja nieco za trudna jak na początek, a zatem przyjrzyjmy się jedynie przykładowi działania
obiektu Television.
Tworzenie instancji
$myTV = new Television;
$myTV->setChannel (2);
$anotherTV = new Television;
$anotherTV->setChannel (4);
print "My TV : " . $myTV->getChannel()."<br>\n";
print "The other TV : " . $anotherTV->getChannel();
Odczytując powyższy kod, od samej góry, znajdujemy obiekt Television o nazwie $myTV. Zawszeg, gdy
tworzymy obiekt w PHP, korzystamy z operatora new. Jest to zabieg nieco inny, niż zwyczajne tworzenie
zmiennej, a nazywamy go tworzeniem instancji — tworzymy tu bowiem instancję klasy Television, tak jak we
Flashu!
Następnie, widzimy wywołanie metody setChannel obiektu $myTV. Jeśli spojrzymy na kod definicji klasy
Television, przekonamy się, że zadaniem tej metody jest przypisywanie wartości $channel do argumentu
setChannel. Ten sam efekt moglibyśmy uzyskać, zapominając o metodzie setChannel i wpisując kod
następujący:
<?
// This is really bad practise!!
$myTV->channel = 2;
?>
Kod zadziała, ale jest on przykładem bardzo niewłaściwej praktyki. Pracę w tym stylu można by porównać do
poszukiwania elektronicznego elementu wewnątrz telewizora, odpowiedzialnego za zmianę kanałów i użycie go
za pomocą połączenia kablami!
Ogólnie rzecz biorąc, w programowaniu obiektowym zawsze należy korzystać z funkcji dostępowych, takich jak
setChannel — odpowiedników przycisków czy gałek na obudowie odbiornika. W ten sposób zyskamy pewność,
że bez względu na to kto będzie korzystał z naszego kodu, zrobi to w sposób, dla jakiego kod został
zaprojektowany. To zaś podnosi używalność i wydajność kodu, a nas czyni szczęśliwymi programistami!
No dobrze, jeśli powrócimy do naszego przykład, zauważymy, że został w nim utworzony nowy obiekt
Television, o nazwie $anotherTV, ustawiony na odbiór kanału 4.
3
Oznacza to, że mamy do czynienia z dwoma obiektami Television, ustawionymi na odbiór dwóch różnych
kanałów, co wydaje się całkiem proste. Tymczasem, jest to jedna z najsilniejszych funkcji programowania
obiektowego. Chcąc dokonać takiej samej operacji w tradycyjny sposób, należałoby napisać bardzo
skomplikowany skrypt. Należałoby, prawdopodobnie, użyć jakiegoś rodzaju tablicy i pętli, by uzyskać ten sam
rezultat.
Konstruktory
Zazwyczaj, tworząc instancję klasy, należy ustawić początkowe wartości właściwości nowego obiektu lub
uruchomić określone funkcje.
W przypadku klasy Television, jak dotąd pomijaliśmy właściwość $make. Jak wspomnieliśmy wcześniej,,
marka telewizora pozostaje niezmienna, a w związku z tym nie mamy możliwości jej zmodyfikowania.
Aby upewnić się, że klasa Television funkcjonuje w ten sam sposób, definiujemy konstruktor. Do definicji klasy
dopisujemy więc następującą funckję:
function Television ($theMake) {
$this->make = $theMake;
}
Konstruktor jest funkcją wywoływaną po utworzeniu instancji klasy. Musi ona nosić dokładnie tę samą nazwę,
co klasa, ale parametry mogą być definiowane dowolnie.
Gdybyśmy zechcieli użyć powyższego konstruktora, nasz kod tworzyłby nowe obiekty Television w
następujący sposób:
$myTV = new Television("A well-known brand");
$myTV->setChannel (2);
$anotherTV = new Television("A competitor brand");
$anotherTV->setChannel (4);
Kod ten jedynie ustawia wartość $make w $myTV jako A well-known brand, zaś w $anotherTV jako A
competitor brand.
Dziedziczenie
No dobrze, podstawy programowania obiektowego mamy już za sobą. Jeśli ktoś nie zrozumiał wszystkiego,
niech się nie przejmuje — do końca niniejszego dodatku poruszać się będziemy w sferze przykładów ze świata
realnego.
Istnieje kilka dalszych zagadnień związanych z programowaniem obiektowym, które należałoby omówić, a
które są nieco bardziej złożone. Pierwszym z nich jest dziedziczenie. Nie będziemy korzystać z tej techniki w
naszym przykładzie, ale pamiętajmy, że jest ona bardzo ważną częścią OOP i z pewnością przekonamy się o jej
użyteczności, tworząc kolejne, własne projekty PHP.
Wyobraźmy sobie drzewo genealogiczne rodziny telewizorów, na szczycie którego spoczywa omawiana już
klasa Television. Poniżej znajdziemy telewizory różnego typu — czarno-białe, szerokoekranowe, kolorowe,
kolorowe z szerokim ekranem i tak dalej.
Rzeczą jasną jest, że wszystkie telewizory bazują na klasie Television, cechując się jednak specyficznymi
przymiotami. Na przykład, telewizory czarno-białe wyświetlają obraz jedynie w odcieniach szarości, telewizory
szerokoekranowe mają możliwość przełączania w tryb szerokiego ekranu lub 16x9.
Załóżmy, że zechcielibyśmy utworzyć nową klasę telewizorów szerokoekranowych. Większość funkcji będzie
taka sama, jak w normalnej klasie Television, a uzupełnimy je tylko kilkoma dodatkowymi.
Moglibyśmy po prostu skopiować i wkleić kod klasy Television, a następnie dodać kilka dalszych funkcji.
Rozwiązanie takie będzie działało, ale co się stanie, gdy stwierdzimy istnienie błędu w oryginalnym kodzie
Television? Należałoby wówczas przeprowadzić naprawę w dwóch miejscach, gdyż kod został powielony.
Jeżeli w przyszłości chcielibyśmy utworzyć kolejne typy telewizorów tą metodą, błędy zostałyby zreplikowane.
Znacznie lepszym rozwiązaniem jest użycie tylko potrzebnych fragmentów klasy Television i uzupełnienie ich o
dodatkowe cechy. Programowanie obiektowe sprawdza się tu doskonale.
<?
class WideScreenTelevision extends Television {
var mode;
4
function WideScreenTelevision($theMake) {
$this->make = $theMake;
$this->mode = true;
}
function toggleWideScreenMode() {
$this->mode = !$this->mode;
}
}
?>
W tym przykładzie zdefiniowaliśmy nową klasę WideScreenTelevision, która rozszerza klasę Television. Słowo
extends jest specjalnym słowem kluczowym i oznacza ono, że definiowana nowa klasa ma dostęp do wszystkich
metod i właściwości klasy rodzicielskiej, czyli w tym przypadku klasy Television.
Tak więc, nowa klasa może korzystać z metod i funkcji Television oraz nowych, które zadeklarujemy.
Przykład powyższy ilustruje mechanizm prostego przełączania telewizora pomiędzy trybami wyświetlania
obrazu szerokoekranowego i normalnego.
Może zainteresować nas fakt, że nie można rozszerzać klas w PHP, ani usuwać żadnych och metod czy
właściwości. Jest to możliwe w innych językach programowania obiektowego, ale nie w PHP.
Chodźmy na zakupy!
A zatem, powinniśmy już wiedzieć przynajmniej czym są obiekty, po co się je tworzy oraz w jaki sposób się je
implementuje. Teraz zajmiemy się przykładem wykorzystania obiektów w praktyce, tworząc prosty koszyk na
zakupy.
Większość sieciowych sklepów na całym świecie bazuje na zaskakująco podobnych systemach zakupowych.
Jestem pewnie, że Czytelnicy znają działanie tego rodzaju usługi. Cały proces wygląda następująco:
Użytkownik odwiedza witrynę, gdzie przydzielony mu zostaje koszyk, do którego wkłada się
nabywane artykuły.
Użytkownik przeszukuje witrynę, odnajdując interesujący go produkt.
Zazwyczaj, obok rysunku produktu znajduje się przycisk Add to basket (Włóż do koszyka), który
użytkownik musi kliknąć.
Dokonany wybór zapisywany jest w koszyku.
Użytkownik dalej przegląda ofertę, ewentualnie wybierając kolejne produkty.
Po wypełnieniu koszyka artykułami, użytkownik naciska przycisk Checkout (Rachunek), wprowadza
dane karty kredytowej, a za kilka dni zakupiony towar ląduje pod jego drzwiami.
Być może niektórzy zakupili tę książkę w taki właśnie sposób!
Proces wygląda na całkiem prosty, ale za jego kulisami jest wiele złożonych mechanizmów.
Działanie procesu bazuje na tym, że witryna potrafi zapamiętywać użytkowników oraz odróżniać ich. Jak dotąd,
rozpatrzyliśmy jedną, prostą metodę zapisu informacji o użytkowniku, do czego wykorzystuje się ciasteczka,
omówione w Rozdziale 6. W niniejszym przykładzie rozszerzymy nieco tę koncepcję i pomówimy na temat
implementacji.
Implementując koszyk zakupowy we Flashu, niektórzy programiści zapisują dane dotyczące poczynionych
zakupów w zmiennych Flasha. Jest to słuszne rozwiązanie, ale czas życia zmiennych Flasha jest ograniczony do
jednej odsłony określonej witryny sieciowej. W niektórych przypadkach, naciśnięcie przycisku Odśwież,
spowodowałoby zatarcie danych o zakupach, gdyż Flash wyzerowałby wszystkie zmienne.
A zatem, rozsądnym rozwiązaniem jest przechowywanie wszystkich zmiennych, potrzebnych podczas całej sesji
(wizyty na witrynie), na serwerze.
Można to osiągnąć, generując cookie z unikalnym identyfikatorem ID w komputerze użytkownika, zaś dane
dotyczące zakupów przechowywać w bazie danych MySQL. Jest to bardzo dobre rozwiązanie, ale może być
zbyt skomplikowane dla niektórych programistów.
Prostsze rozwiązanie polega na zastosowaniu zmiennej sesyjnej, do której uzyskujemy dostęp ze skryptów.
Użyjemy takiej zmiennej tutaj, projektując strukturę aplikacji, której budowę za chwilę rozpoczniemy...
5
Zgłoś jeśli naruszono regulamin