Пусть дан класс 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
своего родителя,
чтобы выполнить часть проверки.