Programowanie zorientowane obiektowo to niewątpliwie jedna z najefektywniejszych i najefektowniejszych metod programowania. W tym artykule przedstawiam to co jest potrzebne do programowania obiektowego w PHP 4.
W miarę jak rozwijało się PHP (już jako język programowania) pojawiały się problemy wielokrotnego użycia kodu. Były co prawda pliki, które można było dołączyć wraz z zestawem potrzebnych funkcji, ale był to mało efektowny sposób. Do PHP zaimplementowano obsługę obiektów. Daleko tej implementacji było do Javy czy Pythona, zarówno pod względem obsługi jak i późniejszego użycia tych obiektów. Obiekty w PHP mają tą samą zasadę działania i są o wiele prostsze w użyciu, nie dają może nieograniczonych możliwości, ale na potrzeby aplikacji internetowych spokojnie wystarczają.
Terminologia obiektowa:
Pojecie obiektu jest nierozłączne z pojęciem klasy. Klasa jest swego rodzaju zbiorem elementów, a jednym z tych elementów jest obiekt, nazywany również egzemplarzem klasy. Klasa jest pojęciem ogólnym, jakby formą, a obiekt jest konkretnym egzemplarzem danej klasy. Dane przechowywane w klasie zwane są właściwościami. Obiekt może korzystać ze zdefiniowanych właściwości w klasie. W klasie można również zdefiniować funkcje, które nazywane są metodami. Do metod oraz właściwości można odwoływać się przez obiekt tylko i wyłącznie wtedy, gdy zostały one wcześniej zdefiniowane w klasie. Obiekt, jak również jego metody i właściwości mogą być traktowane jak zwykłe zmienne i funkcje, czyli np. mogą być przekazywane jako argumenty funkcji.
Terminologia w praktyce:
Dla przykładu definiujemy klasę o nazwie „Banknot”. W klasie „Banknot” określamy właściwości: „Kraj”, „symbol” i „Nazwa”. Określamy również metodę, która będzie prezentowała dany banknot o nazwie „wyswietl()”. Gotowa definicja klasy wygląda następująco:
Class Banknot { //nasze trzy właściwości var $kraj; var $symbol; var $nazwa; function wyswietl() |
Słowo kluczowe VAR przed nazwą zmiennej oznacza, że jest to właściwość dostępna dla wszystkich metod w danej klasie. Do właściwości odwołujemy się poprzez słowo kluczowe this, oznaczające, że odwołanie następuje wewnątrz klasy. Przed nazwą zmiennej nie stawiamy już znaku dolara $ gdyż stoi on przed słowem kluczowym this.
Teraz jest to pusta klasa. Utworzymy teraz dwa obiekty klasy Banknot:
$polski_banknot = new Banknot; $niemiecki_banknot = new Banknot; |
Z chwilą „przypisania” klasy Banknot do zmiennej staje się ona obiektem. W przykładzie posłużę się starą walutą niemiecką (Markami). Przekazuje do właściwości obiektu wartości, gdyż są na razie puste:
$polski_banknot->kraj = „Polska”; $polski_banknot->sumbol = „zł”; $polski_banknot->nazwa = „Złoty”; $niemiecki_banknot->kraj = „Niemcy”; |
Teraz właściwości obu obiektów posiadają wartości. Pamiętaj, że nie możesz odwołać się do właściwości nieokreślonej wcześniej w klasie. Teraz mogę wywołać metody dla dwóch obiektów:
$polski_banknot->wyswietl(); |
Da w wyniku:
Kraj: Polska Symbol: zł Nazwa: Złoty |
Natomiast kod:
$niemiecki_banknot->wyswietl(); |
Da w wyniku:
Kraj: Niemcy Symbol: dm Nazwa: Marka |
Konstruktory:
Można klasę zdefiniować w taki sposób, aby już przy tworzeniu egzemplarzu danej klasy ustawić wartości, można to osiągnąć przy użyciu tzw. Konstruktorów. Konstruktor jest to funkcja wewnątrz definicji klasy, która posiada nazwę identyczną z nazwą klasy. Jest ona wywoływana wraz z określaniem egzemplarzu klasy. Konstruktor do klasy „Banknot” wyglądałby następująco:
function Banknot() { //instrukcje } |
Najlepiej byłoby, aby wyglądał tak:
function Banknot( $kraj, $symbol, $nazwa ) { $this->kraj = $kraj; $this->symbol = $symbol; $this->nazwa = $nazwa; } |
Wówczas tworzenie egzemplarzu klasy Banknot wyglądałoby następująco:
$polski_banknot = new Banknot( „Polska”, „zł”, „Złoty” ); |
Wszystkie właściwości klasy od razu otrzymują podane wartości.
Zasięg nazw:
klasa posiada własne i odrębne pole nazw, tzn., że jeżeli masz w klasie zmienną $kraj, a dalej w programie występuję także zmienna o takiej nazwie to nie wystąpi konflikt. Nie może być konfliktu, ponieważ każdy Obiekt posiada kopię właściwości o takich samych nazwach.
Klasa jako magazyn:
Zmienne (zwane w klasie właściwościami) mają zasięg w całej klasie, tzn. jeżeli ustawiamy w klasie właściwość:
var $kraj; |
Następnie wywołujemy ją przez jedną z metod w klasie, która ją modyfikuje, a dalej wywołujemy inną metodą, która ją wypisuje to ta właściwość dalej będzie posiadała swoją wartość. Gdybyśmy próbowali zrobić to bez klasy, używając do tego dwóch funkcji w programie, wartość nie została by zwrócona, gdyż funkcje po zakończeniu niszczą wszystkie zmienne, a ponieważ posiadają ich wewnętrzne kopie zmienne w programie dalej posiadają własne niezmienione wartości. Można to rozwiązać za pomocą słowa kluczowego „global” co rozwiąże problem, ale może łatwo doprowadzić do konfliktu nazw, a jak pisałem wcześniej w klasie to nie grozi.
Dziedziczenie:
Jeśli chodzi o obiekty to jest to bardzo ważna sprawa. W praktyce pozwala zaoszczędzić trochę miejsca i usprawnić kod. Dziedziczenie pozwala na swego rodzaju połączenie pomiędzy obiektami, tzn. utworzenie pewnej hierarchii. W takiej hierarchii jeden obiekt rozszerza możliwości drugiego. Można powiedzieć że taki obiekt jest potomnym w stosunku do rozszerzającego. Mamy dla przykładu klasę Banknot i chcemy ją rozszerzyć o możliwość zmiany wartości jednej z jej właściwości podczas działania skryptu. Wówczas definiujemy nową klasę, ale nie przepisujemy instrukcji tylko posługujemy się słowem kluczowym „extends”:
class SuperBanknot extends Banknot { function zamien( $wlasciwosc, $wartosc ) { switch ( $wlasciwosc ) { case „kraj”: $this -> kraj = $wartosc; break; case „symbol”: $this -> symbol = $wartosc; break; case „nazwa”: $this -> nazwa = $wartosc; break; default: echo „Nie ma takiej właściwości”; break; } } } |
Klasa Superbanknot zawiera wszystkie właściwości i metody klasy Banknot plus swoje. Jest jednak jedna sprawa nad którą trzeba się zastanowić, a mianowicie konstruktory. Jeżeli klasa potomna (w tym wypadku SuperBanknot) nie posiada konstruktora, wówczas PHP domyślnie uruchomi konstruktor klasy macierzystej, jeżeli jednak klasa potomna ma własny konstruktor, to konstruktor klasy macierzystej trzeba wywołać albo ręcznie, albo w konstruktorze klasy potomnej:
function SuperBanknot { $this -> Banknot(); } |
Konstruktor klasy macierzystej będzie uruchamiany razem z konstruktorem klasy potomnej i w takim wypadku trzeba również podać wartość przy tworzeniu obiektu.
Po co są klasy:
Klasy mnożna traktować jak np. telewizor, czy muszę wiedzieć, co ma w środku, aby go oglądać??? Wystarczy ze pokazuje obraz, można przełączać kanały, robić głośniej, itp. Nie musze wiedzieć jak to się robi. To znacznie ułatwia pracę. Gdy np. pracuje się w team’ie z programistami, używanie klas nie jest może niezbędne, ale ułatwia pracę pod wieloma względami. Nawet do pracy w domu, gdy nie wiem np. jak napisać funkcję, która by wypisywała, kto ma dzisiaj imieniny, taka funkcja musiałaby korzystać z danych w postaci imienin, a gdybyśmy mieli już gotową klasę z właściwością w postaci tablicy z imieninami i odpowiednią metodą wyświetlającą imieniny można by załatwić całą sprawę w prosty sposób:
<? include(„klasa_imieniny.inc”); $imieniny = new klasa_imieniny; |
I po sprawie. Oczywiście trzeba posiadać plik z załączoną klasą, ale przykład miał tylko pokazać przykładowe użycie. Można by tu podawać wiele przykładów użycia klas, ale znając możliwości z pewnością znajdziecie dla nich sensowne zastosowanie. Drugim powodem użycia klas jest znacznie większa estetyka pisanego kodu, nie ma powtarzającego się kodu, nadpisujących się zmiennych, lub kilku kopii tych samych. Namawiam do korzystania z klas i obiektów.