Podejście obiektowe w PHP
W współczesnej informatyce stosuje się często podejście obiektowe, w którym staramy się
wyizolować pewien fragment zadania nadając mu charakter odrębnego obiektu
Fundamentem programowania obiektowego są
pojęcia klasy i obiektu
Klasy i obiekty (1)
Obiektem może być zestaw informacji
dotyczących pewnej książki (autor, tytuł, cena, ...) czy też współrzędne pewnego punktu na ekranie Obiekty tworzone są wg pewnego schematu czy
też planu, który określa jakie elementy składowe zawiera obiekt i jak należy je przetwarzać aby uzyskać potrzebne informacje (np. jak obliczyć cenę książki na podstawie ceny hurtowej) — taki plan obiektu nazywany jest klasą
Klasy i obiekty (2)
Niekiedy mówi się, że klasa to zdefiniowany
przez programistę nowy typ danych
Tworzenie programów obiektowych polega na
definiowaniu klas, opisywaniu związków między nimi i opisywaniu sposobów przetwarzania
obiektów
Przykładowa definicja klasy KLIENT
class KLIENT
{
public $nazwa_klienta;
public $kwota_rachunku;
}
Definiowanie klas
Klasa jest definiowana za pomocą słowa
kluczowego class
Bezpośrednio po słowie class występuje nazwa klasy, i następnie definicja klasy ujęta w nawiasy klamrowe { i }
Klasa może zawierać wiele zmiennych i funkcji dowolnego typu — w takim kontekście zmienne
nazywane są często polami klasy, a funkcje –
metodami klasy
Słowo public (formalnie: specyfikator dostępu) informuje, że dostęp do podanego pola nie jest ograniczony przez dodatkowe warunki
Metody czyli funkcje (1)
Obok opisów pól (zmiennych) wewnątrz definicji klasy występują też funkcje, które tu nazywane są metodami
Metodę klasy tworzy się przy użyciu słowa
kluczowego function
Dalej podano postać przykładowej definicji
metody:
class KLIENT
{
public $nazwa_klienta;
public $kwota_rachunku;
public function oblicz_VAT22 ($kwota)
{
$VAT22 = $kwota * 0.22 ;
return $VAT22 ;
}
}
Kolejność pól i metod
Kolejność pól i metod (funkcji) w definicji klasy może być dowolna, warto jednak stosować
ogólnie przyjętą konwencję i umieszczać na
początku klasy wszystkie pola, po nich zaś —
metody
W języku PHP wymaga się by klasa była
umieszczona w jednym bloku kodu PHP, a
definicje metod muszą znajdować się wewnątrz definicji klasy
Obiekty czyli egzemplarze klasy
Można sobie wyobrazić, że klasa w
programowaniu obiektowym jest odpowiednikiem kliszy drukarskiej zawierającej tekst zeszytu do ćwiczeń dla niższych klas szkoły podstawowej Uczeń wpisuje do zeszytu do swoje imię i
nazwisko, a potem wypełnia dalsze strony wg
zawartych tam poleceń
Zatem konkretny zeszyt nabiera pewnych cech
indywidualnych, ale wszystkie zeszyty zostały wytworzone w oparciu o tę samą kliszę
Tworzenie obiektów
W programowaniu obiektowym mówi się, że
obiekt jest instancją danej klasy (tzn. jest egzemplarzem czy wystąpieniem danej klasy)
Do tworzenia obiektów używa się słowa new, po którym podaje się nazwę klasy, np.:
$klient1 = new KLIENT( );
W podanym przykładzie utworzony obiekt został
przypisany zmiennej $klient1 — pozwala to na wykonywanie działań wykorzystujących elementy składowe obiektu
Odwołania do składowych klasy (1)
Definicja klasy jest definicją typu — klasa opisuje budowę obiektu, określa jego pola i metody
Zdefiniowanie klasy nie powoduje tworzenia
obiektu, przy czym żadne metody nie są
wywoływane — zatem umieszczenie samej tylko
klasy wewnątrz skryptu nie spowoduje żadnych widocznych efektów
Odwołania do składowych klasy (2)
Odwołania do poszczególnych składowych klasy realizuje się za pomocą operatora w postaci
dwóch znaków: −>
Przykładowa instrukcja może mieć postać:
$klient1 −> nazwa_klienta = ’Malinowski’ ; Podana instrukcja powoduje, że pole
nazwa_klienta w obiekcie $klient1 przyjmie wartość ’Malinowski’
Zauważmy, że znak dolara $ pojawia się zawsze jeden raz przed zmienną
Referencja $this (1)
Niekiedy w metodach (funkcjach) występuje
słowo kluczowe $this, które określane jest
również jako referencja $this (w opisie języka PHP występuje też termin pseudo zmienna) Oznacza ono odwołanie do obiektu bieżącego,
np. w odniesieniu do wcześniejszego przykładu wyrażenie
$this −> kwota_rachunku
oznacza pole kwota_rachunku z klasy KLIENT
Referencja $this (2)
Jeśli wewnątrz metody podamy instrukcję, w
której pominięto słowo $this, np.
$kwota_rachunku = 1200
to instrukcja spowoduje utworzenie zmiennej
lokalnej $kwota_rachunku wewnątrz funkcji —
zatem wartość 1200 nie będzie zapisana do pola obiektu, a do zmiennej lokalnej i zostanie
utracona po zakończeniu działania funkcji
Błąd taki nie powoduje sygnalizacji i może być trudny do zauważenia
Konstruktory i destruktory (1)
Po utworzeniu obiektu jego pola nie zawierają żadnych wartości
W wielu przypadkach celowe jest nadanie
wartości początkowych niektórym polom obiektu Przykładowo, jeśli został utworzony obiekt
opisujący klienta, to byłoby pożądane, zanim jeszcze zostaną wykonane inne operacje,
wpisanie wartości 0 do pola $kwota_rachunku
Konstruktory i destruktory (2)
Potrzebne inicjalizacje mogą być wykonane
automatycznie już w trakcie tworzenia obiektu —
trzeba tylko wewnątrz klasy zdefiniować metodę __construct (przed słowem construct występują dwa znaki podkreślenia _) i umieścić w niej
wszystkie niezbędne działania inicjalizacyjne Metoda ta, nazywana konstruktorem, będzie wywoływana automatycznie w chwili tworzenia
każdego nowego obiektu
Konstruktory i destruktory (3)
Przeciwieństwem konstruktorów są destruktory
— metody, które są uruchamiane w chwili
usuwania (kasowania) obiektu
W praktyce programowania PHP destruktory
występują stosunkowo rzadko. Mają one postać metody o nazwie __destruct
Konstruktory i destruktory (4)
Przykład konstruktora klasy KLIENT, który
wpisuje 0 do pola kwota_rachunku:
function __construct ()
{
$this -> kwota_rachunku = 0 ;
}
Mechanizm dziedziczenia
Mechanizm dziedziczenia pozwala budować hierarchię klas, które przejmują swoje
właściwości i stanowi jeden z fundamentów
programowania obiektowego
Mechanizmy dziedziczenia wyjaśnimy na
podstawie dwóch klas przykładowych OSOBA i
PRACOWNIK
Klasa przykładowa OSOBA (1)
Zadaniem klasy OSOBA jest przechowywanie
danych dotyczących osób
Przyjmujemy, że w klasie OSOBA
przechowywane będą imię i nazwisko
Zdefiniujemy też metody pozwalające zapisać i odczytać nazwisko i imię
Omawiana klasa może mieć postać:
<?php
class OSOBA
{
public $imie, $nazwisko ;
//---------------------------------
public function zapiszImie ($imie)
{
$this -> imie = $imie ;
}
//-----------------------------------
public function zapiszNazwisko
($nazwisko)
{
$this -> nazwisko = $nazwisko ;
}
Klasa przykładowa OSOBA (3) public function odczytajImie ()
{
return $this -> imie ;
}
//--------------------------------
public function odczytajNazwisko ()
{
return $this -> nazwisko ;
}
}
?>
Klasa przykładowa PRACOWNIK (1)
W przedstawionej klasie OSOBA zdefiniowano
metody, które pozwalają zarówno na wpisywanie jak i odczytywanie danych osobowych
reprezentowanych przez dwa pola: $imie i
$nazwisko
Tego rodzaju informacje potrzebne są w
najrozmaitszych programach, a w szczególności mogą też wystąpić w innej klasie przykładowej, który nazwiemy PRACOWNIK
Ta klasa z kolei zawierać będzie również pola $imie i $nazwisko oraz pole identyfikatora pracownika $ident_pracownika
Klasa przykładowa PRACOWNIK (2)
W klasie PRACOWNIK trzeba również
zdefiniować metody potrzebne do zapisywania i odczytywania danych osobowych, w tym
identyfikatora pracownika.
Metoda zapiszImie w klasie PRACOWNIK
będzie miała taką postać jak metoda zapiszImie w klasie OSOBA — to samo dotyczy pozostałych metod wykonujących działania na polach imienia i nazwiska
Jedyna różnica dotyczy metod działających na polu $ident_pracownika, które nie występuje w klasie OSOBA
Klasa przykładowa PRACOWNIK (3)
Podane tu rozważania pozwalają na
stwierdzenie, że klasa PRACOWNIK może być
traktowana jako rozszerzenie klasy OSOBA —
zamiast więc pisać całkowicie odrębny kod klasy PRACOWNIK, można spowodować by klasa ta
przejęła (czy odziedziczyła) wszystkie możliwości klasy OSOBA wprowadzając dodatkowo swoje
własne rozszerzenia
Realizacja dziedziczenia w języku PHP (1) W języku PHP dziedziczenie realizowane jest za pomocą słowa extends
Korzystając z mechanizmu dziedziczenia można zdefiniować klasę PRACOWNIK jako
rozszerzenie klasy OSOBA — ilustruje to podany niżej przykład
Realizacja dziedziczenia w języku PHP (2)
<?php
class PRACOWNIK extends OSOBA
{
public $ident_pracownika ;
//-------------------------------------------
public function zapiszIdent ($ident)
{
$this -> ident_pracownika = $ident ;
}
//-------------------------------------------
public function odczytajIdent ()
{
return $this -> ident_pracownika ;
}
}
?>
Klasy bazowe i potomne
Każdy obiekt klasy PRACOWNIK będzie zawierał
również wszystkie pola i metody z klasy OSOBA Klasa, która powstaje poprzez rozszerzenie
istniejącej klasy za pomocą słowa extends nosi nazwę klasy potomnej (pochodnej), a klasa pierwotna nazywana jest klasą bazową
Skrypt przykładowy (1)
W celu ułatwienia uruchamiania programu w PHP
warto kody należące do omawianych tu klas
umieścić w odrębnym pliku o nazwie klasy.php —
plik ten zostanie włączony do programu
głównego poprzez zastosowanie polecenia
include
Na początku tego pliku należy umieścić znaki <?
php, a na końcu znaki ?>.
<?php
include ”klasy.php” ;
$pracownik1 = new PRACOWNIK () ;
$pracownik1 -> zapiszImie(”Stefan”) ;
$pracownik1 ->
zapiszNazwisko(”Malinowski”) ;
$pracownik1 -> zapiszIdent(”705”) ;
echo '<br>Dane obiektu $pracownik1 <br>' ; echo $pracownik1 -> odczytajImie() . ' ' ; echo $pracownik1 -> odczytajNazwisko() .
'<br>' ;
echo 'Identyfikator = ' ;
echo $pracownik1 -> odczytajIdent() .
'<br><br>' ;
?>
Przesłanianie składowych (1)
Możliwość dziedziczenia tworzy potencjalnie
dalsze problemy, które wymagają rozstrzygnięcia W klasie bazowej i w klasie potomnej została zdefiniowana metoda (funkcja) o tej samej
nazwie — w językach obiektowych jest to w pełni akceptowane
Przyjęto, że metoda z klasy bazowej jest
przesłaniana: dokładniej, w obiektach klasy bazowej będzie obowiązywała metoda z klasy
bazowej, a w obiektach klasy pochodnej —
metoda z klasy pochodnej
Przesłanianie składowych (2)
Przykład: w klasie bazowej i potomnej występują dwie metody o tej samej nazwie oblicz
W podanym tu przykładzie metody niczego nie
obliczają, ale jedynie wykonują instrukcję echo, co pozwala na zaobserwowanie ich działania
<?php
class klasa_bazowa
{
public function oblicz()
{
echo (”Wywołano funkcję z klasy bazowej<br>”) ;
}
}
Przesłanianie składowych (3) class klasa_potomna extends klasa_bazowa
{
public function oblicz()
{
echo (”Wywołano funkcję z klasy potomnej<br>”) ;
}
}
$obiekt_B = new klasa_bazowa () ;
$obiekt_P = new klasa_potomna () ;
$obiekt_B -> oblicz() ;
echo (”<br>”) ;
$obiekt_P -> oblicz() ;
?>
Przesłanianie składowych (4)
Niekiedy może się pojawić wymaganie, by w
klasie potomnej wywołać metodę podaną w
klasie bazowej — stosuje się wówczas odwołanie zawierające słowo parent, np.
parent::oblicz() ;
Blokowanie przesłaniania składowych (1)
Stosując techniki opisane w poprzednim punkcie można przesłaniać składowe zdefiniowane w
klasach bazowych
Innymi słowy, metody klasy bazowej mogą być
przeciążane w klasach pochodnych
W niektórych przypadkach może to być
niepożądane — w PHP użycie słowa kluczowego
final oznacza, że składowa nie może
przeciążana
Poniżej podano przykład takiej metody.
Blokowanie przesłaniania składowych (2) final public function odczytajImie ()
{
return $this -> imie ;
}
Konstruktory i destruktory
w klasach bazowych i potomnych
Konstruktory i destruktory są to metody, które wywoływane są automatycznie podczas
tworzenia i kasowania obiektu
W odniesieniu do klas potomnych przyjęto, że wykonywane są jedynie konstruktory i destruktory w nich zdefiniowane, nie są natomiast
wywoływane konstruktory i destruktory klas
bazowych
Specyfikatory dostępu
W języku PHP określa się sposób dostępu do
składowych klasy poprzez określenie
specyfikatora dostępu (modyfikatora dostępu) —
dostępne są trzy specyfikatory:
public — składowa publiczna, do której można się dowolnie odwoływać;
protected — składowa chroniona — dostęp do
takiej składowej jest ograniczony do klasy, w której ta składowa jest zdefiniowana oraz do klas bazowych i pochodnych;
private — dostęp do składowej prywatnych jest ograniczony tylko do klasy, w której ta klasa jest zdefiniowana
Składowe statyczne (1)
Samo zdefiniowanie klasy nie wywołuje żadnych widocznych skutków — dopiero utworzenie
obiektu powoduje, że zaczynają rzeczywiście
istnieć składowe klasy
Składowe statyczne istnieją także wtedy, gdy nie ma żadnego obiektu danej klasy
Składowe statyczne deklaruje się za pomocą
słowa kluczowego static
Ponadto, przy odwoływaniu się do składowych
statycznych nazwę składowej trzeba poprzedzić nazwą klasy ze znakami :: — ilustruje to poniższy przykład
<?php
class NOWA
{
public static $liczba = 254 ;
public static function oblicz ()
{
echo
”Wywołano funkcję statyczną klasy NOWA<br>” ;
}
}
// wyświetlenie wartości składowej $liczba echo "liczba = " . NOWA::$liczba . "<br>" ;
// wpisanie nowej wartości do składowej
// $liczba i ponowne wyświetlenie
NOWA :: $liczba = 512 ;
echo 'liczba = ' . NOWA::$liczba . '<br>' ;
// wywołanie funkcji statycznej
NOWA :: oblicz () ;
?>
Składowe statyczne (4)
Dostęp do składowych statycznych wymaga
stosowania nieco innych konstrukcji
programistycznych — przy odwołaniach do takich składowych z wnętrza klasy używa się słowa
kluczowego self:: , np.:
self :: $liczba = 1200;
lub dla metod (funkcji):
self :: oblicz() ;
Składowe statyczne (5)
W odwołaniach na zewnątrz klasy można
odwoływać się do składowych statycznych, ale tylko będących metodami (funkcjami) —
odwołania takie mają typową postać:
$obiekt_N = new NOWA ;
$obiekt_N -> oblicz();
Wyjątki i ich obsługa (1)
Wyjątki stanowią pewien mechanizm używany
zazwyczaj do obsługi błędów
Programista ma możliwość zgłoszenia wyjątku
(inaczej: wyrzucenia wyjątku) za pomocą instrukcji throw — zazwyczaj jest to informacja o błędzie
W najprostszym przypadku instrukcja taka może mieć postać:
<?php
throw new Exception () ;
?>
Wyjątki i ich obsługa (2)
Parametrem instrukcji throw jest obiekt klasy Exception (utworzony za pomocą instrukcji new) W podanym przykładzie nie są przekazywane
argumenty dla konstruktora, ale w przypadku
ogólnym można opcjonalnie podać komunikat (ciąg znaków), a także kod błędu (wartość całkowita)
Wyjątki i ich obsługa (3)
Wyjątki generowane przez program powinny być obsługiwane powodując, jeśli to możliwe,
wznowienie wykonywania programu, ale też jego zakończenie
Można powiedzieć, że generowane wyjątki
powinny być przechwytywane przez fragmenty kodu zajmujące się obsługą błędów — w tym
celu używa się instrukcji
try...catch
której przykładowe zastosowanie zawiera
poniższy skrypt.
<?php
try
{
throw new Exception () ;
}
catch (Exception $e)
{
echo ”Został wygenerowany wyjątek<br>” ;
}
?>
Wyjątki i ich obsługa (5)
Klasa Exception zawiera kilka metod, które mogą być przydatne do obsługi wyjątków — przykład wykorzystania tych metod pokazany jest poniżej
<?php
try
{
throw new Exception
(”Podano błędne parametry”, 743) ;
}
Wyjątki i ich obsługa (6) catch (Exception $e)
{
echo ”Został wygenerowany wyjątek<br>” ; echo ”Treść komunikatu = ” ;
echo $e -> getMessage() . ”<br>” ; echo ”Kod błędu = ” . $e -> getCode() .
”<br>” ;
echo ”Nazwa pliku = ” . $e -> getFile() . ”
<br>” ;
echo ”Numer linii = ” . $e -> getLine() . ”
<br>” ;
}
?>
<?php
try
{
throw new Exception () ;
}
catch (Exception $e)
{
echo ”Został wygenerowany wyjątek<br>” ;
}
?>