Podejście obiektowe w PHP
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)
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)
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
Przykładowa definicja klasy KLIENT
class KLIENT
{
public $nazwa_klienta;
public $kwota_rachunku;
}
Definiowanie klas
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)
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:
Metody czyli funkcje (2)
Metody czyli funkcje (2)
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
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
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
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)
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 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
Referencja
$this
$this
(1)
(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
Referencja
$this
$this
(2)
(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)
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)
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)
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)
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
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)
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 ;
Klasa przykładowa OSOBA (2)
Klasa przykładowa OSOBA (2)
//---------------------------------
public function zapiszImie ($imie)
{
$this -> imie = $imie ;
}
//-----------------------------------
public function zapiszNazwisko
($nazwisko)
{
$this -> nazwisko = $nazwisko ;
}
Klasa przykładowa OSOBA (3)
Klasa przykładowa OSOBA (3)
public function odczytajImie ()
{
return $this -> imie ;
}
//--------------------------------
public function odczytajNazwisko ()
{
return $this -> nazwisko ;
}
}
?>
Klasa przykładowa PRACOWNIK (1)
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)
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)
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)
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)
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
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)
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 ?>.
Skrypt przykładowy (2)
Skrypt przykładowy (2)
<?php
include ”klasy.php” ;
$pracownik1 = new PRACOWNIK () ;
$pracownik1 -> zapiszImie(”Stefan”) ;
$pracownik1 ->
zapiszNazwisko(”Malinowski”) ;
$pracownik1 -> zapiszIdent(”705”) ;
Skrypt przykładowy (3)
Skrypt przykładowy (3)
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)
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)
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)
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)
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)
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)
Blokowanie przesłaniania składowych (2)
final public function odczytajImie ()
{
return $this -> imie ;
}
Konstruktory i destruktory
Konstruktory i destruktory
w klasach bazowych i potomnych
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
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)
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
Składowe statyczne (2)
Składowe statyczne (2)
<?php
class NOWA
{
public static $liczba = 254 ;
public static function oblicz ()
{
echo
”Wywołano funkcję statyczną klasy NOWA<br>” ;
}
}
Składowe statyczne (3)
Składowe statyczne (3)
// 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)
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)
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 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)
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 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.
Wyjątki i ich obsługa (4)
Wyjątki i ich obsługa (4)
<?php
try
{
throw new Exception () ;
}
catch (Exception $e)
{
echo ”Został wygenerowany wyjątek<br>” ;
}
?>
Wyjątki i ich obsługa (5)
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)
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>” ;
}
?>
Wyjątki i ich obsługa (7)
Wyjątki i ich obsługa (7)
<?php
try
{
throw new Exception () ;
}
catch (Exception $e)
{
echo ”Został wygenerowany wyjątek<br>” ;
}
?>