PHP/Czym jest programowanie obiektowe?

< PHP
Poprzedni rozdział: Ćwiczenia
Następny rozdział: Klasy i obiekty

Czym jest programowanie obiektowe?

edytuj

Dotychczas pisane przez nas skrypty miały charakter strukturalny. Programowanie strukturalne jest proste do opanowania i wystarczające dla podstawowych skryptów, jednak wraz z ich rozrastaniem się panowanie nad coraz większą liczbą funkcji staje się coraz trudniejsze. W tym rozdziale nauczysz się nowej techniki programowania zwanej programowaniem obiektowym, która jest wykorzystywana w niemal wszystkich bardziej zaawansowanych aplikacjach. W założeniu jest ona dość intuicyjna i opiera się na naturalnym postrzeganiu świata przez człowieka, lecz wielu programistów miewa z nią na początku kłopoty. Zalecamy dobre przyłożenie się do tego rozdziału, ponieważ znajomość prezentowanego materiału jest kluczowa do zrozumienia dalszej części podręcznika.

Filozofia programowania obiektowego

edytuj

Programowanie zorientowane obiektowo oparte jest na zupełnie innej filozofii, niż dotychczasowe skrypty, jakie pisaliśmy. Podstawowymi bytami, którymi operujemy, są obiekty oraz klasy, które całkiem nieźle odzwierciedlają rzeczywistość wokół nas. Próba wyrażenia wycieczki do sklepu po zakupy przy pomocy funkcji będzie wyglądać nienaturalnie i zupełnie nieintuicyjnie, tymczasem bardzo łatwo możemy ją opisać obiektami. Idziemy do sklepu i bierzemy jeden z dostępnych obiektów klasy koszyk. Wiemy, że we wszystkich koszykach możemy umieszczać towary. Wędrując wśród półek, do koszyka wrzucamy obiekt klasy chleb, która jest szczególnym przypadkiem towaru. Nasz chlebek znajduje się w koszyku, ale na półce są jeszcze inne takie obiekty, które mogą zostać wzięte przez innych klientów. Bierzemy też masło i jakiś napój (wszystko to obiekty odpowiednich klas) i z tym wszystkim wędrujemy do obiektu kasa, któremu przekazujemy nasz koszyk. W kasie dowiadujemy się, ile pieniędzy musimy przekazać, aby pobrane obiekty stały się nasze. Po zapłaceniu odbieramy nasze obiekty i bierzemy je do domu, czyli obiektu klasy dom.

W tej krótkiej historyjce zawarliśmy wszystkie podstawowe cechy programowania obiektowego. W kodzie naszego programu tworzymy klasy, które opisują pewien rodzaj przedmiotu, definiując jego właściwości oraz zachowania. W sklepie mieliśmy do czynienia z klasą koszyk, o której wiedzieliśmy że:

  • Każdy koszyk ma określoną pojemność (właściwość)
  • W koszykach mogą znajdować się towary (właściwość - lista towarów, które są w koszyku).
  • Do koszyków możemy wrzucać nowe towary (zachowanie).

Wszystkie koszyki w sklepie to obiekty tej klasy. Mają one wszystkie identyczny zestaw właściwości oraz identycznie się zachowują, lecz każdy koszyk jest na swój sposób wyjątkowy. Wzięliśmy obiekt koszyk o pojemności 10 litrów i aktualnie zawiera on chleb, masło i napój. Klient, który przeszedł obok nas, niesie swój własny koszyk o pojemności 15 litrów, w którym niesie warzywa, mąkę i mięso. Są to dwa różne koszyki, jednak zachowujące się tak samo.

 
Dla kasjera każda wędlina jest towarem. Dla klienta nie każdy towar jest wędliną.

W historyjce o wizycie w sklepie mówimy też o towarach, czyli obiektach klasy towar. Powiedzieliśmy także, że "chleb jest towarem". Taki związek nosi nazwę dziedziczenia i również występuje w programowaniu obiektowym. Stwierdzenie to oznacza, że chleb posiada wszystkie właściwości i zachowania towaru (cena, możliwość zmiany ceny przez pracownika), a jednocześnie dodaje nowe, specyficzne dla siebie, np. wagę czy możliwość pokrojenia bochenka na pół, co oczywiście wpłynie też na cenę. Każda klasa może dziedziczyć po dowolnej innej klasie, przejmując jej właściwości i zachowania. Dzięki temu w kasie można wszystko podliczyć. Kasa przetwarza towary, zatem interesuje ją jedynie cena bez względu na to, czy dany towar jest chlebem czy napojem. Gdyby w sklepie była krajalnica, obsługiwałaby ona wyłącznie różne rodzaje chleba - nie możemy położyć na niej napoju, ponieważ tu samo bycie towarem już nie wystarcza; obiekt, który kładziemy, musi być co najmniej chlebem.

Jest też jeszcze jeden aspekt dziedziczenia - klasa dziedzicząca może modyfikować zachowania klasy bazowej. Przypuśćmy, że nasze towary są wyposażone w zachowanie oblicz cenę. W podstawowej wersji podaje ono po prostu wartość właściwości cena, jednak niektóre rodzaje towarów mogą wymagać bardziej złożonych przeliczników. Tak będzie w przypadku warzyw, gdzie cena jest uzależniona od wagi kupowanego towaru. W klasie warzywa możemy zaznaczyć: "w zwykłym towarze po prostu braliśmy podaną cenę, jednak tutaj będziemy uwzględniać wagę". Gdy warzywa trafią do kasy, kasjer oczywiście wykona obliczanie ceny. W tym miejscu możliwe są dwa wyniki:

  • Ponieważ kasjer przetwarza towary, wybierze zawsze zachowanie charakterystyczne dla towaru nawet, gdy będzie kasować warzywa, które powinny być traktowane inaczej.
  • Kasjer przetwarza towary, ale wie, że niektóre towary mogą mieć specyficzne zasady wyceniania i stosuje się do nich.

W tym drugim przypadku mamy do czynienia z tzw. polimorfizmem, czyli z sytuacją, gdy wciąż pamiętamy o prawdziwej naturze obiektu, nawet gdy traktujemy go bardziej ogólnie. W PHP wszystkie zachowania są polimorficzne, dlatego w tym języku obowiązywać Cię będzie wyłącznie druga możliwość. Brak polimorfizmu jest ze względów wydajnościowych stosowany w niektórych językach kompilowanych, jak C++ i wspominamy o nim jedynie przy okazji.

Podsumujmy to, czego zdążyliśmy się dowiedzieć. Wbrew pozorom nowych pojęć nie ma wcale aż tak dużo:

  • Klasy - definiują pewien rodzaj obiektów o określonych właściwościach i zachowaniach
  • Obiekty - rzeczywiste byty, na których pracujemy.
  • Właściwości - pewne informacje charakteryzujące obiekt. W dalszej części będziemy je nazywać "polami" klasy bądź obiektu.
  • Zachowania - definiują, co obiekty danej klasy mogą robić. W dalszej części będziemy je nazywać "metodami".
  • Dziedziczenie - pozwala wyrażać zależności "X jest Y-kiem".
  • Polimorfizm - pamiętanie o prawdziwej naturze obiektów nawet, gdy rozpatrujemy je z punktu widzenia ogólniejszej klasy.

Wiemy już, że programowanie obiektowe świetnie opisuje otaczającą nas rzeczywistość, dlatego teraz zastanowimy się, jak za jego pomocą opisać środowisko programu komputerowego, a w szczególności skryptu strony internetowej.

Programowanie obiektowe w aplikacjach

edytuj

Przejście z poziomu analizy świata rzeczywistego do abstrakcyjnego środowiska programu komputerowego sprawia początkującym programistom wiele trudności. Na pierwszy rzut oka ciężko powiedzieć, co w programie powinno być klasą, ile i jakich obiektów tworzyć oraz jak rozdzielić funkcje programu między klasy, by wszystko miało ręce i nogi? Najlepiej przyglądać się rzeczywistym skryptom. Techniki programowania obiektowego są rozbudowaną dziedziną wiedzy, o której można napisać kilka podręczników takich, jak ten. Nabranie wprawy z pewnością zajmie trochę czasu, dlatego nie zrażaj się początkowymi niepowodzeniami.

W aplikacjach WWW podstawowym zastosowaniem programowania obiektowego jest kontrola nad akcją, którą musimy dla użytkownika wykonać. Przypomnijmy sobie naszą księgę gości. Mieliśmy tam różne akcje w stylu "dodaj wpis" czy "przeglądaj wpisy", które były umieszczone w osobnych plikach oraz wybierane instrukcją **switch**. W kodzie obiektowym stworzymy sobie specjalną klasę bazową Moduł. Stwierdzamy w niej, że moduły mają akcje oraz definiujemy metody pozwalające wywołać akcję o podanej nazwie. Następnie tworzymy sobie specjalizowane klasy reprezentujące poszczególne moduły naszej strony: News, Księga gości itd. Każda klasa zawierać będzie kilka akcji związanych z danym modułem reprezentowanych przez metody. Przykładowo, w klasie Księga gości umieścimy metody wyświetl oraz dodaj wpis.

Tworzymy także kolejną klasę Nadzorca, która będzie potrafiła tworzyć obiekty określonych modułów i żądać od nich wykonania określonych akcji. W obrębie jednego żądania może zostać wykonanych kilka akcji z różnych modułów, dlatego nadzorca musi umieć także przechowywać obiekty tych, które już załadował. Działanie skryptu możemy opisać wtedy następująco:

Przypuśćmy, że chcemy wyświetlić listę wpisów w księdze gości. Dlatego tworzymy obiekt nadzorcy i przekazujemy do niego nazwę odpowiedniego modułu i akcji, po czym każemy mu rozpocząć pracę. Nadzorca załaduje odpowiednią klasę, utworzy jej obiekt i nakaże mu wykonać określoną akcję, dzięki czemu w przeglądarce ujrzymy to, co chcemy zobaczyć.

Zauważmy, że od naszych klas tworzyliśmy jedynie po jednym obiekcie. To nie przypadek i nie pomyłka. Bardzo często zdarza się, że tworzymy klasę tylko po to, by mieć dokładnie jeden jej obiekt (ba, czasami nawet wymuszamy odpowiednim kodem niemożność utworzenia większej liczby obiektów). Na początku wydaje się to dziwne, ale zwróćmy uwagę na kilka rzeczy:

  1. Jeśli tworzymy dużą aplikację, chcielibyśmy, aby była ona w miarę spójna. Skoro już utworzyliśmy kilka klas, warto wszystkie elementy aplikacji przedstawić w takiej postaci nawet, jeśli oznacza to tworzenie tylko pojedynczych ich obiektów.
  2. Obiekty posiadają pola, które są niczym innym, jak kolejnym rodzajem zmiennych. Jest to wygodny sposób organizowania danych w naszej aplikacji, bez bardzo brzydkiego tworzenia zmiennych globalnych, instrukcji **global** itd. W dodatku obiekty posiadają bardzo precyzyjne mechanizmy określające, kto i kiedy może dostać się do wybranych danych, co poprawia niezawodność.
  3. Mając klasę, możemy skorzystać z dziedziczenia. Przecież nasza aplikacja WWW może mieć kilku różnych nadzorców do różnych zastosowań. Zależność "X jest Y-kiem" jest bardzo przydatna, a nie uzyskamy jej tak łatwo przy pomocy zwykłych funkcji.

Kolejne zastosowanie to interakcja z bazami danych, do której przejdziemy tuż po rozdziale poświęconym programowaniu obiektowemu. W bazach danych istnieją dziesiątki elementów o różnorodnej strukturze: artykuły, wiadomości, profile użytkowników. Istnieją specjalne biblioteki zwane ORM (ang. Object-Relational mapper), które przenoszą te elementy do aplikacji właśnie w postaci obiektów.

Słowo końcowe

edytuj

Przedstawione tu informacje mają póki co bardziej teoretyczny charakter, który miał zaznajomić Cię z całą ideą. Począwszy od następnego rozdziału zaczniemy już pisać obiektowy kod w PHP, jednak często będziemy wracać do tego, co zostało tutaj powiedziane. Jeszcze raz przypominamy: informacje, które tu poznasz, są niezbędne do rozumienia dalszej części podręcznika. Mogą wydawać się skomplikowane, ale kiedy już załapiesz, o co w tym wszystkim chodzi, Twoje życie naprawdę stanie się o wiele prostsze.