PHP/Dziedziczenie

Z Wikibooks, biblioteki wolnych podręczników.

< PHP

Poprzedni rozdział: Konstruktory i destruktory Spis treści Następny rozdział: Interfejsy

Spis treści

[edytuj] Dziedziczenie klas

Pisząc obiektowy kod, prędzej (lub później) zajdzie potrzeba pisania klas wg tego samego planu - tym samym powtarzania kilka razy tego samego kodu. Spójrzmy na poniższy przykład:

<?php

        class Lilia
        {
                public $czy_podlany = false;

                public function nazwa() 
                {
                        echo 'Lilia';
                }

                public function podlej() 
                {
                        $this -> czy_podlany = true;
                        echo 'Kwiat zostal podlany';
                }

        }

        class Roza
        {

                public $czy_podlany = false;

                public function nazwa() 
                {
                        echo 'Roza';
                }

                public function podlej() 
                {
                        $this -> czy_podlany = true;
                        echo 'Kwiat zostal podlany';
                }

        }

?>

Jak widać, bardzo duża część kodu została napisana dwa razy. Żeby uniknąć takich sytuacji, programiści dostali mechanizm dziedziczenia.

[edytuj] Czym jest dziedziczenie?

Dziedziczenie oznacza przejmowanie pól i metod przez klasę dziedziczącą. Przykładowo, jeśli rodzic (klasa, której pola i metody dziedziczymy) ma metodę Nazwa(), klasa potomna (dziedzicząca) też będzie posiadać tę metodę, mimo że przeglądając jej kod w edytorze nie znajdziemy jej deklaracji.

[edytuj] Implementacja dziedziczenia

Aby zaznaczyć, że dana klasa jest podklasą innej, stotsujemy słowo kluczowe extends. Umieszczamy je po nazwie klasy, a przed klamrą otwierającą ciało klasy. Po słowie extends wpisujemy nazwę klasy, z której chcemy dziedziczyć. Wracając do naszych kwiatków:

<?php

        class Kwiat
        {
                public $czy_podlany = false;

                public function podlej() 
                {
                        $this -> czy_podlany = true;
                        echo 'Kwiat zostal podlany';
                }

        }

        class Lilia extends Kwiat
        {

                public function nazwa()
                {
                        echo 'Lilia';
                }

        }

        // Teraz swobodnie tworzymy obiekt klasy Lilia
        $lilia = new Lilia();
        // Uzywamy metod z klasy Lilia
        $lilia -> nazwa();
        // Jak i klasy Kwiat
        $lilia -> podlej();

?>

Jak widać, $lilia posiada pola i metody zarówno klasy Kwiat, jak i Lilia.

[edytuj] Unieważnianie

Załóżmy jednak, że mamy nieco inną sytuację - zarówno podklasa, jak i rodzic posiadają metodę o tej samej nazwie:

<?php

        class A
        {
                public function nazwij() 
                {
                        echo 'Jestem klasa A';
                }

        }

        class B extends A
        {

                public function nazwij()
                {
                        echo 'Jestem klasa B';
                }

        }

        // Tworzymy obiekty
        $a = new A();
        $b = new B();
        // I wywolujemy nazwij()
        $a -> nazwij();
        $b -> nazwij();

?>

Otrzymamy 'Jestem klasa AJestem klasa B'. Jak widać, klasa dziedziczy metody pod warunkiem, że nie posiada swoich własnych metod o takiej nazwie. Podobnie sprawa się ma z polami:

<?php

        class A
        {
                public $nazwa = 'A';

                public function nazwij() 
                {
                        echo 'Jestem klasa ' . $this -> nazwa;
                }

        }

        class B extends A
        {

                public $nazwa = 'B';

        }

        // Tworzymy obiekty
        $a = new A();
        $b = new B();
        // I wywolujemy nazwij()
        $a -> nazwij();
        $b -> nazwij();

?>

Efekt będzie taki sam, jak w poprzednim przykładzie.

Czasem możemy jednak nie chcieć unieważniania metod. Wtedy potrzebujemy użyć słowa kluczowego final. Oznacza ono, że klasa, bądź metoda, jest zadeklarowana jako wersja ostateczna, i nie może zostać nadpisana. Jakakolwiek próba unieważnienia metody finalnej (bądź dziedziczenia klasy finalnej) kończy się komunikatem o błędzie.

[edytuj] Kontrola nad dostępem a dziedziczenie

Przypomnijmy sobie słowa kluczowe private i public. Pamiętamy ich znaczenie, prawda? A jak się zachowają one przy dziedziczeniu metod i pól? Public zapewne nic nie zmieni - w końcu oznacza 'dostęp dla każdego'. A private? Private oznacza całkowity zakaz wstępu. Nie wchodzić z zewnątrz, nie dziedziczyć. Zatem brakuje nam rozwiązania pośredniego: brak dostępu z zewnątrz, ale zezwolenie na dziedziczenie. Na szczęście developerzy PHP przewidzieli taką sytuację - wprowadzili słowo kluczowe protected. Oznacza dokładnie tyle, co 'można dziedziczyć, ale nie można użyć spoza klasy'.

<?php

        class Parent
        {
                public function a() 
                {
                        echo 'A';
                }

                protected function b() 
                {
                        echo 'B';
                }

        }

        class Child extends Parent
        {

                public function c()
                {
                        $this -> b();
                }

        }

        // Tworzymy obiekty
        $class = new Parent();
        echo $class -> a(); // Zadziala (zwroci: A)
        echo $class -> b(); // Wyrzuci blad - brak dostepu

        $child = new Child();
        echo $child -> a(); // Zadziala (zwroci: A)
        echo $child -> b(); // Blad - patrz wyzej
        echo $child -> c(); // Zadziala (zwroci: B)

?>

[edytuj] Klasy i metody abstrakcyjne

Znów wróćmy do naszej klasy kwiat. Załóżmy, że potrzebujemy w każdym obiekcie kwiatu metody nazwa(). Ale klasa Kwiat nie posiada takiej metody. Jeśli więc nie chcemy pozwolić na tworzenie obiektów klasy Kwiat, ale chcemy, by inne klasy z niej dziedziczyły, możemy przerobić klasę Kwiat na klasę abstrakcyjną:

<?php

        abstract class Kwiat
        {
                public $czy_podlany = false;

                abstract public function nazwa();

                public function podlej() 
                {
                        $this -> czy_podlany = true;
                        echo 'Kwiat zostal podlany';
                }

        }

?>

Jak widać, aby utworzyć abstrakcyjną klasę, przed słowem kluczowym class trzeba umieścić inne słowo kluczowe - abstract. Teraz próba stworzenia obiektu z klasy Kwiat zakończy się komunikatem błędu. Ale słowo abstract może odnosić się też do metod. Cóż to oznacza? Oznacza to, że klasa dziedzicząca musi zawierać taką samą metodę (z takimi samymi parametrami). Nie wpisujemy natomiast ciała metody - ono jest niezależne w każdej podklasie.

[edytuj] Wielodziedziczenie

[edytuj] Zakończenie