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

Пусть у нас есть вот такой класс 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, в котором будет хранится зарплата работника. Зарплата должна передаваться четвертым параметром в конструктор объекта. Сделайте также геттер для этого свойства.