ООП. Наследование классов в php

cats dolls ООП. Наследование классов в php Классы в php версии 5 могут наследоваться, т.е. приобретать свойства и методы своего родителя. А зачем вообще нужно наследование классов?

Рассмотрим наследование на примере человека. Я – человек. И я наследую некоторые свойства класса Человек, например возможность говорить, интеллект, необходимость в воздухе, воде, пище и всяких витаминах. Эти свойства не уникальны для каждого отдельного человека, т.е. всем людям присуще то, что я перечислил. Мы еще можем заметить, что класс Человек наследует зависимость от воды, воздуха и пищи у класса Млекопитающие. А этот класс наследует эти свойства у класса Животные.

Благодаря наследованию мы можем очень много сэкономить на описании реального объекта. Например, спросите меня – что такое утка? Я отвечу: это птица, которая крякает. Я вроде бы сказал всего 4 слова, но полностью в этих четырех словах уместилась вся необходимая информация для описания утки, потому что сказав «птица, которая крякает», я дал вам знать, что утке присущи все свойства птицы плюс свойство «кряканье» icon smile ООП. Наследование классов в php

Наследуем

Короче тем самым объектно-ориентированные языки позволяют создавать модели, очень близкие к реальному миру. Для примера студентов и аспирантов мы можем сказать, что аспирант – это не простой студент. Он обладает дополнительными свойствами, но одновременно он обладает и всеми свойствами студента. Поэтому мы можем унаследовать класс GraduateStudent (аспирант) от класса Student (студент) с помощью ключевого слова extends:

<?
    class Student {
    }
    class GraduateStudent extends Student {
    }
?>

Тут класс Student будет называться базовым, а класс GraduateStudent – производным.

Наследование еще позволяет нам избавиться от повторения кода, потому что все открытые (public, protected) методы и свойства класса Student становятся доступными и в классе GraduateStudent. Помните, в статье ранее я говорил, что модификаторы доступа методов/свойств private и protected отличаются? Вот. Если у нас есть свойство (или метод) private в классе Student, то оно не будет доступно в классе GraduateStudent:

<?
    class Student {
        private   $mark;
        protected $average;
    }

    class GraduateStudent extends Student {

        function someFn() {
            $this->mark = 5;      // Ошибка доступа!
            $this->average = 4.4; // А так правильно
        }

    }
?>

Кстати. Помните, что если свойство или метод в классе не имеют модификатора доступа, то по умолчанию они public? Видимо это было введено для совместимости с предыдущими версиями пхп, где модификаторов еще не было, а все члены класса были публичными.

Вспомним еще конструкторы и деструкторы. Так вот, если нам надо вызвать конструктор или деструктор базового класса, то надо это делать явно, через указатель parent:

<?
    class MyClass {
        function __construct() {
            echo "Запущен конструктор базового класса";
        }
        function __destruct() {
            echo "Запущен деструктор базового класса";
        }
    }

    class MyClass1 extends MyClass {
        function __construct() {
            parent::__construct();
        }
        function __destruct() {
            parent::__destruct();
        }
    }  

    $obj = new MyClass1(); // Выводит "Запущен конструктор базового класса"
    unset($obj);           // Выводит "Запущен деструктор базового класса"
?>

Сейчас это может показаться лишним, но в реальной практике это зачастую очень нужно. Я знаю это по собственному опыту написания программ на C#.

Абстрактные классы и методы

Это тоже новинка в PHP5. Абстрактные методы имеют только объявление и не имеют реализации. Класс, который содержит такие методы, должен быть обязательно объявлен как абстрактный:

<?
    abstract class MyClass {
        abstract public function fn();
    }
?>

Т.е. если бы мы написали так…

<?
    abstract class MyClass {
        abstract public function fn() {
        }
    }
?>

…интерпретатор пхп заругался бы на нас.

Абстрактные классы могут еще содержать и обычные (не абстрактные) элементы. Создать объект абстрактного класса мы не имеем права. Можно только определять новые классы от базового абстрактного класса и создавать объекты уже от производных классов.

А зачем тогда нужны абстрактные методы и классы? А чтобы описать объект, который будет реализован, но который еще не реализован.

А здесь я приведу пример, как использовать абстрактный метод базового класса в производном классе:

<?
    abstract class MyClass {
        abstract public function fn();
    }

    class MyClass1 extends MyClass {
        public function fn() {
            echo “привет”;
        }
    }

    $obj = new MyClass1;
    $obj->fn(); // Выводит “привет”
?>

Интерфейсы

В моем понимании интерфейс – нечто, с помощью чего мы можем управлять объектом. Например, возьмем телевизор. У него есть интерфейс – панель с кнопками спереди под экраном или справа (слева) от экрана. Ну пульт управления – это тоже интерфейс. Т.е. большинство из нас не знает, как сделан телевизор и как он работает, но мы знаем, как им можно управлять (переключать каналы, настраивать громкость, яркость и т.д.). То же самое было придумано и в программировании.

С точки зрения программиста, интерфейс (interface) – это абстрактный класс, который содержит только абстрактные методы и не имеет никаких свойств.

Основное отличие интерфейсов от абстрактных классов – в том, что в PHP 5 класс не может быть порожден от нескольких классов (и абстрактных в т.ч.), но зато может быть создан на основе любого числа интерфейсов. При этом в интерфейсе методы должны объявляться ключевым словом function без указания всяких спецификаторов (в т.ч. и abstract):

<?
    interface Inter1 {
        function fn1();
    }

    interface Inter2 {
        function fn2();
    }

    class MyClass implements Inter1, Inter2 {
        public function fn1() {
            echo 1;
        }
        public function fn2() {
            echo 2;
        }
    }
    $obj = new MyClass;
    $obj->fn1(); // Выведет 1
    $obj->fn2(); // Выведет 2
?>

Также в ООП есть такое понятие, как множественное наследование. Суть его в том, что один и тот же класс может иметь несколько базовых классов. Но для PHP5 это не совсем справедливо. В PHP5 класс не может быть унаследован от нескольких базовых классов, но зато может реализовать сколько угодно интерфейсов, как показано в последнем примере.

Финальные методы и классы

Интересная возможность в пхп 5, на которую я наткнулся в ходе изучения ООП, – это возможность определять финальные методы и классы.

Метод, который мы определили с ключевым словом final, в дальнейшем мы не можем переопределить в классах, которые производны от нашего класса:

<?
    class MyClass {
        final public function fn() {
            // Код метода
        }
    }
    class MyClass1 extends MyClass {
        // Следующий код вызывает ошибку
        // переопределения финального метода
        // базового класса MyClass
        public function fn() {
            // Код метода
        }
    }
?>

И еще: если мы используем final при определении самого класса, то не сможем больше породить от него другие классы:

<?
    final class MyClass {
        // Код описания класса
    }

    // Следующий код вызывает ошибку
    // порождения от финального класса
    class MyClass1 extends MyClass {
        // Код описания класса
    }
?>

Тут заметим, что если класс определен как final, то и все методы этого класса автоматически станут финальными, и определять их явно как final уже не надо.

А как насчет свойств? Свойства класса определять финальными нельзя. Ну в этом не было бы смысла, думаю. Потому что, в отличие от методов, мы не можем переопределять свойства класса. Мы можем их только наследовать.

Выводы

На этом я почти заканчиваю рассмотрение объектно-ориентированного программирования в PHP5. Осталась только одна очень важная вещь – это полиморфизм. Но о ней я вскоре расскажу в другой статье. Надеюсь, я доступно объяснил то, что сам недавно изучил icon smile ООП. Наследование классов в php





Читайте также:



15 Ответов на “ООП. Наследование классов в php”

  1. 3eka
    Июль 14th, 2008

    Вы забыли удалить слово abstract при корпировании кода (там, где “Т.е. если бы мы написали так…”) :)

  2. novice
    Июль 14th, 2008

    Нет, я там ничего не забыл. Смысл написанного “Т.е. если бы мы написали так…” был в том, чтобы показать, что абстрактный метод не имеет тела. Там мной приведено два примера: первый – без тела, второй – с телом. Просто этого не заметно с первого взгляда.

  3. slayersilence
    Март 12th, 2009

    сп, статья порадовала, лаконична:).

  4. Jenia
    Июль 8th, 2009

    ага, объяснили все доступно, спасибо, но самое главное лаконично, после прочтения последней строчки, мог не успел взорваться ))

  5. ageent
    Декабрь 9th, 2009

    Статья хорошо написана. молодец

  6. bloodtar
    Декабрь 15th, 2009

    Скажите, из-за чего может дочерний класс не наследовать переменные?
    у меня именно так и происходит, хотя даже ошибок нет и не выдает:(

  7. grinder
    Апрель 14th, 2010

    думаю из-за того что они объявлены как private-переменные)) я новичок)) так что прошу сильно не ругать))

  8. tylik
    Апрель 29th, 2010

    Классная статья, еще можно добавить про статичные методы и св-ва

  9. ochenhoroshiyparenvasyadaushiykomment
    Июнь 16th, 2010

    Спасибо, статья очень помогла!

  10. greatperson
    Сентябрь 14th, 2010

    А можно совсем глупый вопрос задать? Можно? Спасибо, щас задам.

    Нахрена вообще в PHP интерфейсы?

    Я понимаю, для чего нужны интерфейсы, например, в Java. Когда два класса MyClass1 и MyClass2 реализуют один и тот же интерфейс Inter1, то их обоих можно будет передавать в функцию, которая принимает параметр типа Inter1. Поскольку в Java строгая типизация, то это важно: если передать функции что-то не то, то компилятор заругается.

    Но в PHP-то интерфейсы тогда зачем? Тут же нет строгой проверки по значению. Неважно, реализуют MyClass1 и MyClass2 интерфейс Inter1, или просто каждый из них независимо содержит функцию fn1() – всё равно с ними можно будет без проблем работать, держа в уме что они “как бы реализуют Inter1″. Так какой тогда смысл в наследовании? Чисто идеологически, что ли, для собственного понимания?

    На мой взгляд, в PHP эти интерфейсы никому не нужны. А вот множетственное наследование не помешало бы… :-(

  11. Тормоз
    Октябрь 9th, 2010

    Сейчас изучаю ООП в PHP для своего нового проекта, наткнулся на эту статью, спасибо, многое понял. Вот только мне, как и комментатору до меня, совсем не понятно, на кой чёрт нужно объявление интерфейсов, если там всё равно нет рабочего кода?

    С абстрактными классами ещё можно придумать применение (хотя тоже не очень понятно), а вот с интерфейсами? Странно.

  12. [...] вам понять принцип наследования в PHP. Иначе выражаясь, наследования классов в PHP выгодно для каждого [...]

  13. Tankha
    Декабрь 26th, 2010

    Интерфейсы видимо нужны только для наглядности кода, при разработке несколькими программистами.
    Грубо говоря интерфейс – это директивный комментарий :)

  14. мнительный
    Март 24th, 2011

    мне казалось что строчка (во втором из примеров)
    $this->mark = 5; // Ошибка доступа!
    не должна вызывать никакой ошибки просто создаст своё свойство “новое” mark в созданном объекте.

    проверил – скопировал пример классов с наследованием, создал объект класса GraduateStudent, вызвал метод someFn(), но никакой ошибки.
    Что-то с чем-то не так?

  15. Павел Третьяков
    Апрель 5th, 2011

    Вот таких бы статеек побольше. В общем порадовала меня, всё на пальцах! Только один фиг, не доперло до меня зачем нужны абстрактные классы (и методы)! Как он может на примере применяться… хоть кусочек кода ^^

Оставить комментарий


© 2008 - 2012 i-novice.net | Все права защищены.