Пусть у нас есть вот такой класс User
,
у которого свойства name
и age
задаются в конструкторе и в дальнейшем доступны
только для чтения (то есть приватные и имеют
только геттеры, но не сеттеры):
<?php
class User
{
private $name;
private $age;
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
public function getName()
{
return $this->name;
}
public function getAge()
{
return $this->age;
}
}
?>
От этого класса наследует класс Student
:
<?php
class Student extends User
{
private $course;
public function getCourse()
{
return $this->course;
}
}
?>
Класс-потомок не имеет своего конструктора - это значит что при создании объекта класса сработает конструктор родителя:
<?php
$student = new Student('john', 19); // сработает конструктор родителя
echo $student->getName(); // выведет 'john'
echo $student->getAge(); // выведет 19
?>
Все замечательно, но есть проблема: мы бы
хотели при создании объекта класса Student
третьим параметром передавать еще и курс, вот так:
<?php
$student = new Student('john', 19, 2); // это пока не работает
?>
Самое простое, что можно сделать, это переопределить конструктор родителя своим конструктором, забрав из родителя его код:
<?php
class Student extends User
{
private $course;
// Конструктор объекта:
public function __construct($name, $age, $course)
{
// Дублируем код конструктора родителя:
$this->name = $name;
$this->age = $age;
// Наш код:
$this->course = $course;
}
public function getCourse()
{
return $this->course;
}
}
?>
При этом мы в классе потомке обращаемся к
приватным свойствам родителя name
и age
, что, конечно же, не будет работать
так, как нам нужно. Переделаем их на protected
:
<?php
class User
{
protected $name; // объявим свойство защищенным
protected $age; // объявим свойство защищенным
// Конструктор объекта:
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
public function getName()
{
return $this->name;
}
public function getAge()
{
return $this->age;
}
}
?>
Теперь при создании студента третьим параметром мы можем передать и курс:
<?php
$student = new Student('john', 19, 2); // теперь это работает
echo $student->getName(); // выведет 'john'
echo $student->getAge(); // выведет 19
echo $student->getCourse(); // выведет 2
?>
Не подсматривая в мой код реализуйте такой
же класс Student
, наследующий от User
.
Используем конструктор родителя
Понятно, что дублирование кода родителя в классе потомке - это не очень хорошо. Давайте вместо дублирования кода в конструкторе потомка вызовем конструктор родителя.
Для полной ясности распишу все по шагам.
Вот так выглядит конструктор класса User
,
он принимает два параметра $name
и
$age
и записывает их в соответствующие
свойства:
<?php
// Конструктор объекта класса User:
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
?>
Вот конструктор класса Student
, который
мы хотим переписать:
<?php
// Конструктор объекта класса Student:
public function __construct($name, $age, $course)
{
// Этот код хотим заменить на вызов конструктора родителя:
$this->name = $name;
$this->age = $age;
// Наш код:
$this->course = $course;
}
?>
Конструктор родителя можно вызвать внутри
потомка с помощью parent
. При этом
конструктор родителя первым параметром ожидает
имя, а вторым - возраст, и мы должны ему
их передать, вот так:
<?php
// Конструктор объекта класса Student:
public function __construct($name, $age, $course)
{
// Вызовем конструктор родителя, передав ему два параметра:
parent::__construct($name, $age);
// Запишем свойство course:
$this->course = $course;
}
?>
Напишем полный код класса Student
:
<?php
class Student extends User
{
private $course;
// Конструктор объекта:
public function __construct($name, $age, $course)
{
parent::__construct($name, $age); // вызываем конструктор родителя
$this->course = $course;
}
public function getCourse()
{
return $this->course;
}
}
?>
Проверим, что все работает:
<?php
$student = new Student('john', 19, 2);
echo $student->getName(); // выведет 'john'
echo $student->getAge(); // выведет 19
echo $student->getCourse(); // выведет 2
?>
Так как класс Student
теперь не обращается
напрямую к свойствам name
и age
родителя, можно их опять сделать приватными:
<?php
class User
{
private $name; // объявим свойство приватным
private $age; // объявим свойство приватным
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
public function getName()
{
return $this->name;
}
public function getAge()
{
return $this->age;
}
}
?>
Сделайте класс User
, в котором будут
следующие свойства только для чтения: name
и surname
. Начальные значения этих
свойств должны устанавливаться в конструкторе.
Сделайте также геттеры этих свойств.
Модифицируйте предыдущую задачу так, чтобы
третьим параметром в конструктор передавалась
дата рождения работника в формате год-месяц-день.
Запишите ее в свойство birthday
. Сделайте геттер
для этого свойства.
Модифицируйте предыдущую задачу так, чтобы
был приватный метод calculateAge
,
который параметром будет принимать дату рождения,
а возвращать возраст с учетом того, был ли
уже день рождения в этом году, или нет.
Модифицируйте предыдущую задачу так, чтобы
метод calculateAge
вызывался в конструкторе объекта, рассчитывал
возраст пользователя и записывал его в приватное
свойство age
. Сделайте геттер для
этого свойства.
Сделайте класс Employee
, который будет
наследовать от класса User
. Пусть
новый класс имеет свойство salary
,
в котором будет хранится зарплата работника.
Зарплата должна передаваться четвертым параметром
в конструктор объекта. Сделайте также геттер
для этого свойства.