Podstawy programowania II dr inż. Paweł Róg 1 Zagadnienia % Zagadnienia zaawansowane ą Pola stałe. ą Polimorfizm. ą Klasy i metody abstrakcyjne. ą Interfejsy. ą Klasy i metody finalne. ą Informacja o typie w czasie wykonania. ą Magiczne metody. 2 Pola stałe % Pola stałe definiujemy za pomocą słowa const. class Produkt { protected $typ; protected $nazwa; const FUNTY_NA_KG = 0.45359237; // ... } 3 Pola stałe % Odwołanie do stałej z wnętrza klasy: self::FUNTY_NA_KG; % Odwołanie do stałej z zewnątrz: Produkt::FUNTY_NA_KG; 4 Pola stałe % Wartości stałego pola nie można zmienić, można jednak nadpisać takie pole w klasie pochodnej: class klasaA { const STALA_LICZBA=5; } class klasaB extends klasaA { const STALA_LICZBA=21; } print klasaA::STALA_LICZBA . ' '; print klasaB::STALA_LICZBA ; 5 Polimorfizm Polimorfizm (wielopostaciowość) jest mechanizmem Polimorfizm (wielopostaciowość) jest mechanizmem programowania obiektowego polegającym na programowania obiektowego polegającym na dynamicznym dynamicznym określaniu zachowania obiektu w trakcie określaniu zachowania obiektu w trakcie działania działania programu na podstawie jego rzeczywistego programu na podstawie jego rzeczywistego typu. typu. % Jako przykład rozpatrzmy hierarchię klas implementującą proste obiekty graficzne . % Klasą bazową dla wszystkich obiektów będzie klasa Figura. % Najważniejszą metodą w tej hierarchii klas będzie metoda rysuj() wyświetlająca figurę na ekranie. % Pozostałe klasy (Kwadrat, Trojkat, Kolo) będą dziedziczyć po klasie Figura i dostarczać własną implementację metody rysuj(). 6 class Figura { public function rysuj() { print "Rysuję bezkształtną figurę... "; } } class Kwadrat extends Figura { public function rysuj() { print "Rysuję kwadrat! "; } } 7 class Trojkat extends Figura { public function rysuj() { print "Rysuję trójkąt! "; } } class Kolo extends Figura { public function rysuj() { print "Rysuję koło! "; } } 8 funkcja rysowanie(Figura $f) { print "Inne operacje... "; $f->rysuj(); } for (int $i=0; $i<10; $i++) { $losowa = rand(1,3); switch ($losowa) { case 1 : $figury[$i] = new Kwadrat(); break; case 2 : $figury[$i] = new Trojkat(); break; default: $figury[$i] = new Kolo(); } foreach ($figury as $f) { rysowanie($f); } 9 Klasy abstrakcyjne % W poprzednim przykładzie widać bardzo wyraznie, że nie ma sensu tworzyć obiektu klasy Figura, gdyż wywołanie dla niego metody rysuj() nie ma większego sensu. Z drugiej strony, klasa Figura nadaje się bardzo dobrze na klasę bazową dla innych, konkretnych klas figur. Fakt ten możemy wyrazić, czyniąc klasę Figura klasą abstrakcyjną: abstract class Figura { public function rysuj() { print "Rysuję bezkształtną figurę... "; } } 0 1 Metody abstrakcyjne % Abstrakcyjna klasa Figura nie dostarcza sensownej implementacji dla metody rysuj() i dlatego naturalne będzie określenie, że metoda ta jest abstrakcyjna. W ten sposób dajemy do zrozumienia, że sensowna implementacja tej metody dostarczona zostanie przez klasy pochodne: abstract class Figura { abstract public function rysuj(); } } 1 1 Interfejsy % Możemy iść jeszcze dalej i zastrzec, że Figura deklaruje jedynie interfejs, który musi być zaimplementowany przez konkretne klasy figur: interface Figura { public function rysuj(); } } class Kwadrat implements Figura { public function rysuj() { print "Rysuję kwadrat! "; } } 2 1 Klasy finalne % Jeśli chcemy, aby z danej klasy nie można było wyprowadzać klas potomnych, należy definicję klasy poprzedzić modyfikatorem final: final class Kwadrat implements Figura { public function rysuj() { print "Rysuję kwadrat! "; } } 3 1 Metody finalne % Jeśli chcemy, aby dana metoda nie mogła zostać nadpisana w klasie pochodnej, należy definicję tej metody poprzedzić modyfikatorem final: class Kwadrat implements Figura { final public function rysuj() { print "Rysuję kwadrat! "; } } 4 1 Powtórzenie % Aby zadeklarować pole stałe w klasie należy użyć modyfikatora const. % Wartość stałego pola nie może być zmieniona w czasie wykonania programu, można jednak nadpisać stałe pole w klasie pochodnej. % Polimorfizm (wielopostaciowość) jest mechanizmem programowania obiektowego polegającym na dynamicznym określaniu zachowania obiektu w trakcie działania programu na podstawie jego rzeczywistego typu. % Jeśli chcemy, aby klasa mogła być klasą pochodną dla innych klas, ale nie ma sensu tworzyć obiektów tej klasy, powinna być ona klasą abstrakcyjną (abstract). 5 1 Powtórzenie % Jeśli jakaś klasa jest na tyle wysoko w hierarchii klas, że nie wszystkie jej metody mogą być sensownie zaimplementowane, metody te należy uczynić abstrakcyjnymi. % Interfejs (interface) deklaruje, co może być zrobione, ale nie mówi jak. Dopiero klasa, która implementuje (implements) interfejs dostarcza konkretnych implementacji metod. % Jeśli z jakichś względów nie chcemy, aby dana klasa mogła być klasą bazową dla innych klas, musimy zadeklarować ja jako final. % Jeśli nie chcemy, aby jakaś metoda mogła być nadpisana w klasach pochodnych, również musimy uczynić ją final. 6 1 Informacja o typie w czasie wykonania % get_class() % get_parent_class() % is_subclass_of() % instanceof 7 1 get_class() % Aby w trakcie działania programu otrzymać typ danego obiektu możemy wykorzystać funkcję get_class(): $figura = new Kwadrat(); print get_class($figura); 8 1 get_parent_class() % Aby w trakcie działania programu otrzymać typ klasy bazowej dla danego obiektu możemy wykorzystać funkcję get_parent_class(): $kwadrat = new Kwadrat(); print get_parent_class($kwadrat); 9 1 is_subclass_of % Aby sprawdzić, czy dany obiekt jest obiektem klasy, która jest klasą pochodną wobec innej klasy, możemy użyć funkcji is_subcalss_of(): $kwadrat = new Kwadrat(); if (is_subclass_of($kwadrat, 'Figura')) { print 'OK'; } 0 2 instanceof % Podobne działanie do funkcji is_subclass_of() ma operator instanceof, z tą różnicą, że instanceof pozwala sprawdzić również, czy dany obiekt implementuje dany interfejs: $kwadrat = new Kwadrat(); if ($kwadrat instanceof Figura) { print 'OK'; } 1 2 Zastosowanie instanceof function rysowanie ($cos) { if ($cos instanceof Figura) { $cos->rysuj(); } else { print 'Tego czegoś nie da się narysować...'; } 2 2 Magiczne metody % __toString() % __get() % __set() 3 2 __toString() % Magiczna metoda __toString() umożliwia automatyczne otrzymanie tekstowej reprezentacji obiektu: class Kwadrat extends Figura { // ... public function __toString() { return 'KWADRAT'; } } $kwadrat = new Kwadrat(); print $kwadrat; 4 2 __get() i __set() class Leniwa { protected $_props; public function __get($nazwa) { if (isset($this->_props[$nazwa]){ return $this->_props[$nazwa]; } else { return false; } } public function __set($nazwa, $wartosc) { $this->_props[$nazwa] = $wartosc; } } 5 2