- Наследование в PHP
- Модификаторы доступа
- Вызов родительского метода
- Создать класс потомок php
- Фильтрация данных с помощью zend-filter
- Контекстное экранирование с помощью zend-escaper
- Подключение Zend модулей к Expressive
- Совет: отправка информации в Google Analytics через API
- Подборка PHP песочниц
- Совет: активация отображения всех ошибок в PHP
- Наследование классов
- Несколько потомков
- Наследование от наследников
Наследование в PHP
В этом уроке мы поговорим об ещё одном ките ООП – наследовании. Начнём урок, опять же, с аналогий наследования в реальной жизни.
Котики бывают двух полов: мальчики и девочки. Все мы прекрасно понимаем, чем они отличаются. Однако, у них есть и общие черты – независимо от пола и у тех и у тех есть четыре лапы, есть хвост, голова, усы и далее по списку. То есть есть что-то общее, а есть что-то, что их отличает. Так сказать, детали реализации.
В природе таких примеров уйма – это деление существ по классам и царствам, разделение по половому признаку, разделение по расовой принадлежности, и так далее. Любую вещь можно отнести к какому-то классу, а по каким-то другим признакам – отличить её от других вещей.
Так вот в программировании очень часто встречаются аналогичные ситуации, когда какой-то сущности (или нескольким сущностям) нужно повторить то же, что есть у другой сущности, но с какими-то дополнительными возможностями.
Предположим, на сайте есть простые записи в блоге. У них есть заголовок и текст. Администратор их может редактировать, добавлять что-то новое. А есть посты-уроки, как тот, что вы читаете прямо сейчас. И они должны иметь те же свойства и уметь делать всё то же самое, что и обычные посты, но вдобавок ко всему, у них должна быть домашка.
Давайте создадим для простых записей в блоге класс Post. Пусть, с некоторыми упрощениями, он выглядит так:
class Post < private $title; private $text; public function __construct(string $title, string $text) < $this->title = $title; $this->text = $text; > public function getTitle() < return $this->title; > public function setTitle($title): void < $this->title = $title; > public function getText() < return $this->text; > public function setText($text): void < $this->text = $text; > >
Неужели, для того чтобы сделать класс урока с домашкой нам нужно копировать весь этот код в новый класс Lesson, а затем добавлять новое свойство homework и добавлять геттер и сеттер?
Оказывается – нет. Благодаря наследованию, разумеется. Как это работает? Да проще простого!
Класс может унаследовать от другого класса свойства и методы. Делается это при помощи ключевого слова extends (англ. — расширять). Вот так:
class Lesson extends Post < //тут уже тело класса Lesson >
Класс Lesson называют классом-наследником, или дочерним классом. Класс Post – родительский класс.
В качестве родительского класса при помощи слова extends можно указать только один класс. Однако, у класса Lesson, в свою очередь, тоже могут быть наследники. Они унаследуют все свойства и методы всех своих родителей.
При этом доступными внутри объектов класса-наследника будут только свойства или методы, объявленные в родительском классе как public или protected. Свойства и методы, с модификатором доступа private не будут унаследованы дочерними классами.
То есть, если мы хотим в классе Lesson объявить метод, который будет работать со свойствами title и text, то мы должны определить эти свойства не как private, а как protected:
Теперь мы можем работать с ними и в классе Lesson:
class Lesson extends Post < private $homework; public function __construct(string $title, string $text, string $homework) < $this->title = $title; $this->text = $text; $this->homework = $homework; > public function getHomework(): string < return $this->homework; > public function setHomework(string $homework): void < $this->homework = $homework; > >
Вот таким нехитрым образом мы расширили класс Lesson, унаследовав его от класса Post. Как видим, мы избежали копирования кода, что не может не радовать.
При этом в объектах класса Lesson нам так же доступны все protected- и public-методы, объявленные в родительском классе. Давайте убедимся, в этом.
$lesson = new Lesson('Заголовок', 'Текст', 'Домашка'); echo 'Название урока: ' . $lesson->getTitle();
Как видим, всё прекрасно работает.
Модификаторы доступа
Давайте теперь вернёмся к модификаторам доступа и до конца проясним ситуацию, как каждый модификатор влияет на методы и свойства:
- private – доступны только внутри этого класса, недоступны в классах-наследниках;
- protected – доступны внутри этого класса и всем классам-наследникам. При этом недоступны извне;
- public – доступны как внутри объектов класса, так и снаружи – можем напрямую обращаться к ним извне. Доступны классам-наследникам.
Все public-свойства и методы, то есть то, что позволяет нам напрямую взаимодействовать с объектами извне, называются интерфейсом класса.
Это, опять-таки, относится к инкапсуляции.
Вызов родительского метода
Если присмотреться к классам Post и Lesson, то можно заметить некоторое дублирование кода в конструкторе. Мы и там и там выполняем одинаковые действия для свойств title и text. Было бы неплохо от этого избавиться, воспользовавшись в Lesson уже готовым функционалом из Post.
Для этого мы можем вызвать родительский конструктор в конструкторе дочернего класса. Делается это при помощи ключевого слова parent и двойного двоеточия.
class Lesson extends Post < private $homework; public function __construct(string $title, string $text, string $homework) < parent::__construct($title, $text); $this->homework = $homework; > .
Что именно произойдёт? В момент вызова конструктора класса Lesson (при создании нового объекта), сначала произойдёт вызов метода __construct из родительского класса, а затем задастся свойство homework. При этом этот метод из родительского класса отработает для свойств класса-наследника. Можно представить, что мы просто скопировали сюда содержимое этого метода из класса Post и вставили его сюда. Именно так и происходит, когда этот код выполняется.
Давайте проверим что всё работает:
$lesson = new Lesson('Заголовок', 'Текст', 'Домашка'); var_dump($lesson);
object(Lesson)[1] private 'homework' => string 'Домашка' (length=14) protected 'title' => string 'Заголовок' (length=18) protected 'text' => string 'Текст' (length=10)
Как видим, всё успешно отработало и мы получили то, что хотели.
Вызывать с помощью parent:: можно не только конструктор, но и любой другой метод.
Как видим, тема наследования тесно связана с темой инкапсуляции. Одно без другого не работает. Уберёте одно – и другое сломается. На этом с наследованием всё, делайте домашку, а потом переходите к изучению полиморфизма.
Обратите внимание, что если у родительского класса есть метод с модификатором public/protected, который работает со свойствами или методами с модификатором private, то используя этот метод извне или в дочерних классах мы будем иметь доступ к приватным свойствам через этот публичный метод.
То есть если у класса Post сделать приватными свойства title и text, но при этом в этом классе будет публичный конструктор, который с ними работает, как-то вот так:
class Post < private $title; private $text; public function __construct(string $title, string $text) < $this->title = $title; $this->text = $text; >
то можно в дочернем классе просто вызвать конструктор родительского класса:
class Lesson extends Post < private $homework; public function __construct(string $title, string $text, string $homework) < parent::__construct($title, $text); $this->homework = $homework; >
И через него мы получим доступ к приватным свойствам класса Post.
Полный код, получившийся в ходе урока:
title = $title; $this->text = $text; > public function getTitle() < return $this->title; > public function setTitle($title): void < $this->title = $title; > public function getText() < return $this->text; > public function setText($text): void < $this->text = $text; > > class Lesson extends Post < private $homework; public function __construct(string $title, string $text, string $homework) < parent::__construct($title, $text); $this->homework = $homework; > public function getHomework(): string < return $this->homework; > public function setHomework(string $homework): void < $this->homework = $homework; > > $lesson = new Lesson('Заголовок', 'Текст', 'Домашка'); var_dump($lesson);
Создать класс потомок php
В этом разделе помещены уроки по PHP скриптам, которые Вы сможете использовать на своих ресурсах.
Фильтрация данных с помощью zend-filter
Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.
Контекстное экранирование с помощью zend-escaper
Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.
Подключение Zend модулей к Expressive
Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.
Совет: отправка информации в Google Analytics через API
Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.
Подборка PHP песочниц
Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.
Совет: активация отображения всех ошибок в PHP
При поднятии PHP проекта на новом рабочем окружении могут возникнуть ошибки отображение которых изначально скрыто базовыми настройками. Это можно исправить, прописав несколько команд.
Наследование классов
Представьте, что у вас есть класс User . Он нужен вам для каких-то целей и в общем-то полностью вас устраивает — доработки этому классу в не нужны.
А теперь представим себе ситуацию, когда нам понадобился еще и класс Employee . Работник очень похож на юзера, имеет те же свойства и методы, но еще и добавляет свои — свойство salary , а также геттер и сеттер для этого свойства. Вот этот класс:
salary; > // Сеттер зарплаты public function setSalary($salary) < $this->salary = $salary; > public function getName() < return $this->age; > public function setName($name) < $this->name = $name; > public function getAge() < return $this->age; > public function setAge($age) < $this->age = $age; > > ?>?php>
Как мы видим, код классов User и Employee практически полностью совпадает. Было бы намного лучше сделать так, чтобы общая часть была записана только в одном месте.
Для решения проблемы существует такая вещь, как . С помощью наследования мы можем заставить наш класс Employee позаимствовать () методы и свойства класса User и просто дополнить их своими методами и свойствами.
Класс, от которого наследуют называется ( англ. parent ), а класс, который наследует — . Класс-потомок наследует только публичные методы и свойства, но не приватные.
Наследование реализуется с помощью ключевого слова extends (переводится как расширяет ). Перепишем наш класс Employee так, чтобы он наследовал от User :
Проверим работу нового класса Employee :
setSalary(1000); // метод класса Employee $employee->setName(‘john’); // метод унаследован от родителя $employee->setAge(25); // метод унаследован от родителя echo $employee->getSalary(); // метод класса Employee echo $employee->getName(); // метод унаследован от родителя echo $employee->getAge(); // метод унаследован от родителя ?>?php>
Класс-потомок не унаследовал от своего родителя приватные свойства name и age — попытка обратится к ним вызовет ошибку. При этом, однако, в классе-потомке доступны геттеры и сеттеры этих свойств, так как эти геттеры и сеттеры являются публичными.
Не подсматривая в мой код реализуйте такие же классы User , Employee .
Несколько потомков
Преимущества наследования в том, что каждый класс может несколько потомков. Давайте посмотрим на примере. Пусть кроме работника нам нужен еще и класс Student — давайте также унаследуем его от User :
Проверим работу нашего класса:
setCourse(3); // метод класса Student $student->setName(‘john’); // метод унаследован от родителя $student->setAge(25); // метод унаследован от родителя echo $student->getCourse(); // метод класса Student echo $student->getName(); // метод унаследован от родителя echo $student->getAge(); // метод унаследован от родителя ?>?php>
Не подсматривая в мой код реализуйте такой же класс Student , наследующий от класса User .
Наследование от наследников
Пусть у нас есть класс-родитель и класс-потомок. От этого потомка также могут наследовать другие классы, от его потомков другие и так далее. Для примера пусть от класса User наследует Student , а от него в свою очередь наследует класс StudentBSU :
Сделайте класс Programmer , который будет наследовать от класса Employee . Пусть новый класс имеет свойство langs , в котором будет хранится массив языков, которыми владеет программист. Сделайте также геттер и сеттер для этого свойства.
Сделайте класс Driver ( водитель ), который будет наследовать от класса Employee . Пусть новый класс добавляет следующие свойства: водительский стаж, категория вождения (A, B, C, D), а также геттеры и сеттеры к ним.