Перезапись методов родителя в классе потомке

Пусть дан класс User с приватными свойствами name и age, а также геттерами и сеттерами этих свойств. При этом в сеттере возраста выполняется проверка возраста на то, что он равен или больше 18 лет:

<?php class User { private $name; private $age; public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function getAge() { return $this->age; } public function setAge($age) { if ($age >= 18) { $this->age = $age; } } } ?>

От класса User наследует класс Student с приватным свойством course, его геттером и сеттером:

<?php class Student extends User { private $course; public function getCourse() { return $this->course; } public function setCourse($course) { $this->course = $course; } } ?>

Предположим теперь, что метод setAge, который Student наследует от User нам чем-то не подходит, например, нам нужна также проверка того, что возраст студента до 25 лет.

То есть проверка на то, что возраст более 18 лет нас устраивает, но хотелось бы иметь добавочную проверку на то, что он меньше 25.

Для решения проблемы мы используем то, что в PHP в классе-потомке разрешено сделать метод с таким же именем, как и у родителя, таким образом переопределив этот метод родителя на свой.

Как раз то, что нам нужно.

Итак, давайте напишем свой setAge в классе Student. Наш метод будет проверять то, что возраст студента от 18 до 25 лет:

<?php class Student extends User { private $course; // Перезаписываем метод родителя: public function setAge($age) { if ($age >= 18 and $age <= 25) { $this->age = $age; } } public function getCourse() { return $this->course; } public function setCourse($course) { $this->course = $course; } } ?>

Так как наш метод setAge использует свойство age от родителя, то в родителе это свойство надо объявить как защищенное:

<?php class User { private $name; protected $age; // изменим модификатор доступа на protected public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function getAge() { return $this->age; } public function setAge($age) { if ($age >= 18) { $this->age = $age; } } } ?>

Давайте проверим работу переопределенного метода setAge:

<?php $student = new Student; $student->setAge(24); // укажем корректный возраст echo $student->getAge(); // выведет 24 - возраст поменялся $student->setAge(30); // укажем некорректный возраст echo $student->getAge(); // выведет 24 - возраст не поменялся ?>

Работа с parent

Сейчас в нашем новом методе setAge мы выполняем проверку того, что возраст от 18 до 25 лет. Однако, проверку, того, что возраст от 18 лет выполняет и метод setAge родителя. Это значит, что если мы захотим изменить нижнюю границу возраста - нам придется сделать это в двух местах: в коде класса родителя и в коде класса потомка.

Было бы удобно, если мы метод setAge потомка мог использовать метод setAge от родителя, ведь в методе родителя расположена часть кода, которая нам подходит и мы не хотим ее дублировать в методе потомка.

Такое можно сделать с помощью ключевого слова parent, указывающего на родителя. С его помощью к переопределенному методу родителя можно обратиться так: parent::setAge(), то есть ключевое слово parent, затем два двоеточия и сам метод.

Давайте доработаем наш класс Student так, чтобы использовался метод setAge родителя:

<?php class Student extends User { private $course; public function setAge($age) { // Если возраст меньше или равен 25: if ($age <= 25) { // Вызываем метод родителя: parent::setAge($age); // в родителе выполняется проверка age >= 18 } } public function getCourse() { return $this->course; } public function setCourse($course) { $this->course = $course; } } ?>

Мы добились того, что хотели. Более того, теперь метод setAge потомка не использует свойство age напрямую. Это значит, что в классе-родителе можно поменять его модификатор доступа с protected обратно на private.

Модифицируйте код класса User так, чтобы в методе setName выполнялась проверка того, что длина имени более 3-х символов.

Добавьте в класс Student метод setName, в котором будет выполняться проверка того, что длина имени более 3-х символов и менее 10 символов. Пусть этот метод использует метод setName своего родителя, чтобы выполнить часть проверки.