background image

1

Podstawy programowania II

dr inż. Paweł Róg  

background image

2

Zagadnienia

Zagadnienia zaawansowane

Pola stałe.

Polimorfizm.

Klasy i metody abstrakcyjne.

Interfejsy.

Klasy i metody finalne.

Informacja o typie w czasie wykonania.

Magiczne metody.

background image

3

Pola stałe

Pola stałe definiujemy za pomocą słowa const

class Produkt {

  protected $typ;
  protected $nazwa;

  

const FUNTY_NA_KG = 0.45359237;

  // ...

}

background image

4

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;

background image

5

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 . '<br />';

print klasaB::STALA_LICZBA ;

background image

6

Polimorfizm

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 (KwadratTrojkatKolo) będą 

dziedziczyć po klasie Figura i dostarczać własną 

implementację metody rysuj().

Polimorfizm  (wielopostaciowość)  jest  mechanizmem 

programowania 

obiektowego 

polegającym 

na 

dynamicznym  określaniu  zachowania  obiektu  w  trakcie 

działania  programu  na  podstawie  jego  rzeczywistego 

typu.

Polimorfizm  (wielopostaciowość)  jest  mechanizmem 

programowania 

obiektowego 

polegającym 

na 

dynamicznym  określaniu  zachowania  obiektu  w  trakcie 

działania  programu  na  podstawie  jego  rzeczywistego 

typu.

background image

7

class Figura {

  public function 

rysuj()

 {

    print "Rysuję bezkształtną 
figurę...<br />";

  }
}

class Kwadrat extends Figura {

   public function 

rysuj()

 {

    print "Rysuję kwadrat!<br />";

  }

background image

8

class Trojkat extends Figura {

   public function 

rysuj()

 {

    print "Rysuję trójkąt!<br />";
  }

}

class Kolo extends Figura {
   public function 

rysuj()

 {

    print "Rysuję koło!<br />";
  }

}

background image

9

funkcja rysowanie(Figura $f) {
  print "Inne operacje...<br / >";
  $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);
}

background image

10

Klasy abstrakcyjne

W poprzednim przykładzie widać bardzo wyraźnie, ż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ę...<br />";
  }

}

background image

11

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();

  }

}

background image

12

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!<br />";

  }
}

background image

13

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!<br />";

  }
}

background image

14

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!<br />";

  }
}

background image

15

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).

background image

16

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

.

background image

17

Informacja o typie w czasie wykonania

get_class()

get_parent_class()

is_subclass_of()

instanceof

background image

18

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);

background image

19

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);

background image

20

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';
}

background image

21

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';
}

background image

22

Zastosowanie instanceof

function rysowanie ($cos) {

if ($cos 

instanceof

 Figura) {

   $cos->rysuj();
} else {

   print 'Tego czegoś nie da się 
narysować...';

}

background image

23

Magiczne metody

__toString()

__get()

__set()

background image

24

__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;

background image

25

__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;
  }
}


Document Outline