Dodatek_B-02.doc

(1362 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.

·         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.

 

Rysunek 470.1.

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.

Rysunek 471.1.

Jeśli więc dodamy owe metody do definicji klasy Television, otrzymamy następujący kod:

 

<?

    class Television {

        // Właściwości klasy

        var $volume;

        var $channel;

        var $make;

 

        // Konstruktor

        function Television ($theMake) {

            $make = $theMake;

        }

 

        // Metody klasy

        function increaseVolume() {

            // Zwiększamy głośność o jednostkę

            $this->volume++;

        }

 

        function decreaseVolume() {

            // Odejmujemy jednostkę od aktualnej głośności

            $this->volume--;

        }

 

        function setChannel($newChannel) {

            // Ustawiamy kanał na newChannel

            $this->channel = $newChannel;

        }

 

        function getChannel() {

            // Zwracamy kanał bieżący

            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. Zawsze, 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:

 

<?

    // Ta naprawdę bardzo złe rozwiązanie!!

    $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.

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 16´9.

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;

 

    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.

...

Zgłoś jeśli naruszono regulamin