POWRÓT NA STRONĘ SZKOŁY

Pojęcia związane z programowaniem obiektowym

Podczas tych zajęć pokażemy kilka pojęć związanych z programowaniem obiektowym.

Konstruktory i destruktory

Konstruktor, to nic innego jak metoda wywoływana automatycznie podczas tworzenia obiektu. Posiada specjalną zarezerwowaną dla siebie nazwę __costruct() (na początku podwójny podkreślnik). W naszej definicji bardzo prostej klasy Przyciski, utworzonej podczas poprzednich zajęć, nie umieśliśmy deklaracji kontruktora. Konstruktory mogą jednak wykonywać szereg bardzo ważnych działań, jak np. nadawanie właściwościom pożądanych wartości początkowych, albo tworzenie innych obiektów wymaganych przez tworzony obiekt. Konstruktory to metody, które mogą posiadać parametry ale nie zwracają wartości.

Ćwiczenie 9_2_0_1. Deklaracja konstruktora

Dla uproszczenia zastosujemy jeden plik konstruktor.php

<!doctype html>
<html>
  <head>
    <title>PHP obiektowy</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <?php
      class klasa_php
      {
        public $wlasciwosc;
        function __construct()
        {
          $this->wlasciwosc='Jakaś właściwość';
        }
        public function metoda()
        {
          echo $this->wlasciwosc;
        }
      }
      
      $obiekt=new klasa_php();
      $obiekt->metoda();
    ?> 
  </body>
</html>

Definiując klasę klasa_php określiliśmy jedną właściwość $wlasciwosc (nazwa może byc dowolna, daliśmy $wlasciwosc dla jednoczesnej orientacji co to jest), oraz metodę metoda() . Konstruktor został wywołany automatycznie podczas tworzenia obiektu $obiekt=new klasa_php();. Wywołana w kodzie metoda $obiekt->metoda(); wyświetla wartość właściwości $wlasciwosc nadaną w definicji konstruktora: $this->wlasciwosc='Jakaś właściwość';.

Destruktory są przeciwieństwem konstruktorów, tzn. są wywoływane automatycznie podczas niszczenia obiektów, mają nazwę __destruct() i nie mogą posiadać parametrów ani też zwracać wartości. PHP nie narzuca obowiązku niszczenia obiektu, po jego wykorzystaniu. Obiekt automatycznie przestaje istnieć w momencie usunięcia wszystkich prowadzących do niego referencji. Obiekt można zniszczyć podobnie jak każdą zmienną za pomocą funkcji unset($obiekt);.

Ćwiczenie 9_2_0_2. Deklaracja destruktora

Zastosujemy jeden plik destruktor.php, tym razem pokazany jest tylko kod PHP:

<?php
  class klasa_php
  {
    public $napis;
    function __destruct()
    {
      echo $this->napis;
    }
    public function metoda()
    {
      $this->napis='Ten tekst będzie wyświetlony podczas niszczenia obiektu';
    }
  }      
  $obiekt=new klasa_php();
  $obiekt->metoda();
  unset($obiekt);
?>

Podczas niszczenia obiektu $obiekt, wykonana zostaje instrukcja wyświetlenia własciwości $napis, instrukcja ta jest zawarta w destruktorze.

Kontrola dostępu przy użyciu public i private

Wiemy już że klasa łączy w sobie właściwości i metody. Programista, który korzysta z klasy przygotowanej przez innego programistę nie musi znać wewnętrznego działania tej klasy, wystarczy, że będzie korzystał z udostępnionego przez tę klasę interfejsu, a więc metod opatrzonych dyrektywami public. Takie właśnie modyfikatory dostępu stosowaliśmy do tej pory w naszych przykładach.

Połączenie właściwości i metod w obrębie klasy nazywa się hermetyzacją lub kapsułkowaniem (ang. encapsulation). Hermetyzacja stanowi podstawę programowania obiektowego.

Stosuje się następujące modyfikatory dostępu:

  • public - nieograniczony dostęp do elementu klasy;
  • private - element jest dostępny tylko wewnątrz klasy;
  • protected - dostęp do elementu posiada klasa oraz podklasy tej klasy (o mechaniźmie dziedziczenia dowiesz się dalej)

Jeżeli w deklaracji elementu klasy, nie została wykorzystana żadna z tych dyrektyw, to domyślnie przypisywany jest jej nieograniczony zakres widoczności public.

Ćwiczenie 9_2_0_3. Zastosowanie dyrektyw public i private

Zastosujemy jeden plik dostep.php:

<?php
  class klasa_php
  {
    public $napis_public='napis public<br />';
    private $napis_private='napis private<br />';
    
    public function metoda_public()
    {
      echo 'metoda public<br />';
    }
    private function metoda_private()
    {
      echo 'metoda private<br />';
    }
  }      
  $obiekt=new klasa_php();
  echo $obiekt->napis_public;
  $obiekt->metoda_public();
  echo $obiekt->napis_private;
  $obiekt->metoda_private();
?> 
</body>

Jak widać, dostęp mamy tylko do właściwości i metod public.

Dziedziczenie

Dziedziczenie umożliwia wykorzystanie istniejącego kodu bez konieczności jego kopiowania czy modyfikacji. Klasa potomna dziedziczy po klasie - przodku wszystkie elementy public oraz protected. W PHP klasa może mieć tylko jedną klasę-przodka, może mieć natomiast dowolną liczbę klas potomnych.

Ćwiczenie 9_2_0_4. Przykład dziedziczenia

Zastosujemy jeden plik dziedziczenie.php:

<?php
  class A
  {
    var $wlasciwosc1='właściwość public klasy A';
    protected $a=3;
    
    public function metoda_public()
    {
      echo 'metoda public klasy A';
    }
  }      
  
  class B extends A
  {
    var $b=4;
    public function suma()
    {
     echo $this->b + $this->a;
    }
  }
  
  $obiekt=new B();
  echo $obiekt->wlasciwosc1.'<br />';
  $obiekt->metoda_public();echo '<br />';
  $obiekt->suma();
  $obiekt->$a;
?>
  • Klasa B jest podklasą klasy A (która jest nadklasą), dzięki zastosowaniu słowa kluczowego extends. Można się spotkać również z określeniami klasy wywiedzionej (u nas A wywiedziona z B) z klasy bazowej (u nas B) oraz pojęciem rodzic ( u nas klasa A) i dziecko (u nas B).
  • Zapis var $wlasciwosc1 (var - ang. variable, pol. zmienna), oznacza to samo co public $wlasciwosc1.
  • Klasa B odziedziczyła po klasie A właściwość $wlasciwosc1 oraz metodę metoda_public(). Zwróć uwagę, że zostały one zadeklarowane w klasie A, natomiast wywołujemy je z poziomu obiektu $obiekt, który jest egzemplarzem klasy B.
  • Dzięki odpowiedniemu stosowaniu modyfikatorów private i protected, można kontrolować, które elementy będą dziedziczone. Elementy deklarowane jako private nie są dziedziczone, natomiast jako protected są dziedziczone ale podobnie jak private nie są widoczne na zewnątrz klasy. Element $a został odziedziczony i zastosowany w funkcji suma(), jednak próba wywołania tego elementu z poziomu klasy B kończy się informacją o błędzie.

Ćwiczenie 9_2_0_5. Nadpisywanie (unieważnianie) podczas dziedziczenia

Zastosujemy jeden plik uniewaznianie.php:

<?php
  class A
  {
    var $a=1;
    public function metoda1()
    {
      echo 'metoda oryginalna';
    }
  }      
  
  class B extends A
  {
    var $a=4;
    public function metoda1()
    {
      echo 'metoda nadpisana';
    }
    public function metoda_oryg()
    {
      parent::metoda1();
    }
  }      
  
  $obiekt=new B();
  echo $obiekt->a.'<br />';
  $obiekt->metoda1();echo '<br />';
  $obiekt->metoda_oryg();echo '<br />';
?>

Ponowne zadeklarowanie właściwości i funkcji w klasie potomnej napisuje elementy zadeklarowane w klasie przodka.

  • Właściwość $a oraz metoda metoda1 zadeklarowane w klasie A zostały nadpisane w klasie B.
  • Istnieje sposób na odwołanie się do pierwotnych metod - deklarowanych w klasie bazowej. Umożliwia to zapis parent::metoda1();.

Ćwiczenie 9_2_0_6. Uniemożliwienie dziedziczenia

Metody klasy - przodka oznaczone słowem kluczowym final nie mogą być przedefiniowywane w klasie potomnej.

Zastosujemy jeden plik uniemozliwienie.php:

<?php
  class A
  {
    var $a=1;
    final function metoda()
    {
      echo 'metoda oryginalna';
    }
  }      
  
  class B extends A
  {
    var $a=4;
    public function metoda()
    {
      echo 'metoda nadpisana';
    }
  }      
  
  $obiekt=new B();
  echo $obiekt->a.'<br />';
  $obiekt->metoda();
?>

Próba nadpisania metody zakończyła się komunikatem o błędzie.

Polimorfizm

Polimorfizm to dosłownie wielopostaciowość (gr. polys – wiele, morfe – kształt). W informatyce są tak nazywane mechanizmy pozwalające programiście używać wartości, zmiennych i podprogramów na kilka różnych sposobów. W programowaniu obiektowym polimorfizm oznacza, że te same metody stosowane w różnych klasach mogą przebiegać różnie.

Ćwiczenie 9_2_0_7. Przykład polimorfizmu

Zastosujemy jeden plik polimorfizm.php:

<?php
  class A 
  {
    function echo_tekst()
    {
        echo 'metoda klasy A';
    }

    function wyswietl()
    {
      $this->echo_tekst();
    }
  }      
  
  class B extends A
  {
    function echo_tekst()
    {
        echo 'metoda klasy B';
    }
  }      
  
  $o1=new A;
  $o1->wyswietl();
  
  echo '<br />';
  
  $o2=new B;
  $o2->wyswietl();      
?>
  • Klasa A zawiera dwie metody echo_tekst() oraz wyswietl(). Obie metody są zwykłymi funkcjami o zasięgu publicznym. Jeśli utworzymy obiekt $o1 klasy A i wywołamy jego metodę wyswietl(), to wewnątrz metody wyswietl() zostaje wywołana metoda echo_tekst() klasy A, która wyświetla tekst metoda klasy A.
  • Klasa B jest klasą potomną klasy A i również ma metodę echo_tekst(), która nadpisuje metodę klasy A. Jeżeli teraz utworzymy obiekt $o2 klasy B i wywołamy odziedziczoną metodę wyswietl(), to zostanie wywołana metoda echo_tekst() klasy B, która tym razem wyświetli tekst metoda klasy B.
  • Mamy więc tę samą metodę wyswietl(), która w przypadku obiektów $o1 oraz $o2 wyświetla różne teksty. Takie zachowanie obiektów jest właśnie określane mianem polimorfizmu.