How to Call the Parent Constructor
Summary: in this tutorial, you’ll learn how to call the parent constructor from the constructor of the child class.
Child class doesn’t have a constructor
In the inheritance tutorial, you have learned how to define the SavingAccount class that inherits the BankAccount class:
However, we haven’t discussed the constructors of the parent and child classes in the context of inheritance.
The following adds a constructor to the BankAccount class, which accepts the $balance parameter. The constructor assigns the $balance argument to the $balance property:
class BankAccount < private $balance; public function __construct($balance) < $this->balance = $balance; > public function getBalance() < return $this->balance; > public function deposit($amount) < if ($amount > 0) < $this->balance += $amount; > return $this; > >
Code language: HTML, XML (xml)
The SavingAccount class remains the same and doesn’t include its own constructor:
class SavingAccount extends BankAccount < private $interestRate; public function setInterestRate($interestRate) < $this->interestRate = $interestRate; > public function addInterest() < // calculate interest $interest = $this->interestRate * $this->getBalance(); // deposit interest to the balance $this->deposit($interest); > >
Code language: HTML, XML (xml)
When you create a new instance of the SavingAccount , PHP will call the constructor of the SavingAccount class. However, PHP cannot find the constructor in the SavingAccount class . Therefore, it continues to search for the constructor of the parent class of the SavingAccount class, which is the BankAccount class. And it invokes the constructor of the BankAccount class.
If you don’t pass an argument to the constructor of the SavingAccount class, you’ll get an error:
$account = new SavingAccount();
Code language: PHP (php)
Fatal error: Uncaught ArgumentCountError: Too few arguments to function BankAccount::__construct( ), 0 passed in . on line 5 and exactly 1 expected in .
Code language: JavaScript (javascript)
But if you pass an argument to the constructor, it’ll work perfectly:
$account = new SavingAccount(100);
Code language: PHP (php)
Define a constructor in the child class
A child class can have its own constructor. For example, you can add a constructor to the SavingAccount class as follows:
class SavingAccount extends BankAccount < private $interestRate; public function __construct($interestRate) < $this->interestRate = $interestRate; > public function setInterestRate($interestRate) < $this->interestRate = $interestRate; > public function addInterest() < // calculate interest $interest = $this->interestRate * $this->getBalance(); // deposit interest to the balance $this->deposit($interest); > >
Code language: HTML, XML (xml)
The SavingAccount class has a constructor that initializes the interestRate property.
When a child class has its own constructor, the constructor in the child class will not call the constructor of its parent class automatically.
For example, the following creates a new instance of the SavingAccount class and initializes the $interestRate property to the value 0.05
$account = new SavingAccount(0.05);
Code language: PHP (php)
To call the constructor of the parent class from the constructor of the child class, you use the parent::__construct(arguments) syntax.
The following changes the constructor of the SavingAccount class that accepts two arguments: balance & interest rate. It also calls the constructor of the BankAccount class to initialize the $balance property:
class SavingAccount extends BankAccount < private $interestRate; public function __construct($balance, $interestRate) < parent::__construct($balance); $this->interestRate = $interestRate; > public function setInterestRate($interestRate) < $this->interestRate = $interestRate; > public function addInterest() < // calculate interest $interest = $this->interestRate * $this->getBalance(); // deposit interest to the balance $this->deposit($interest); > >
Code language: HTML, XML (xml)
The syntax for calling the parent constructor is the same as a regular method.
class BankAccount < private $balance; public function __construct($balance) < $this->balance = $balance; > public function getBalance() < return $this->balance; > public function deposit($amount) < if ($amount > 0) < $this->balance += $amount; > return $this; > > class SavingAccount extends BankAccount < private $interestRate; public function __construct($balance, $interestRate) < parent::__construct($balance); $this->interestRate = $interestRate; > public function setInterestRate($interestRate) < $this->interestRate = $interestRate; > public function addInterest() < $interest = $this->interestRate * $this->getBalance(); $this->deposit($interest); > > $account = new SavingAccount(100, 0.05); $account->addInterest(); echo $account->getBalance();
Code language: HTML, XML (xml)
The following class diagram illustrates inheritance between the SavingAccount and BankAccount classes:
Summary
- The constructor of the child class doesn’t automatically call the constructor of its parent class.
- Use parent::__construct(arguments) to call the parent constructor from the constructor in the child class.
Как создать конструктор в расширяемом классе?
Как в контроллере приложения создать конструктор? Это нужно, чтобы во всех контроллерах был общий функционал, нужно в этот конструктор поместить, например такой код
$this->test[‘b’] = 2;
Спасибо.
Простой 7 комментариев
parent?
Станислав, я если добавляю parent, то он требует параметр $this->route, а если я добавляю параметр, то у меня в базовом контроллере $route не заполнена и отваливаются индексы 🙁
Артём Рыженький, А вот нечего инжектить в метод тогда(есть варианты когда это норм, типа как симфони, но это отдельная тема).
Смотри, я сделал так. Это очень криво и написано «за 5минут», но работает.
ps повторюсь что это говонокод и так делать не стоит)
Конструкторы, определенные в классах-родителях не вызываются автоматически, если дочерний класс определяет собственный конструктор. Чтобы вызвать конструктор, объявленный в родительском классе, требуется вызвать parent::__construct() внутри конструктора дочернего класса. Если в дочернем классе не определен конструктор, то он может быть унаследован от родительского класса как обычный метод (если он не был определен как приватный).
class BaseClass < function __construct() < print "Конструктор класса BaseClass\n"; >> class SubClass extends BaseClass < function __construct() < parent::__construct(); print "Конструктор класса SubClass\n"; >>
если бы всё было так, как я прочитал уже давно в доках, то я бы не писал этот вопрос на полэкрана )))
я если добавляю parent, то он требует параметр $this->route, а если я добавляю параметр, то у меня в базовом контроллере отваливаются индексы в $route 🙁
индекс controller не найден
индекс action не найден
сори уважаемый, убрал public из public function __construct() и шторм даже сразу автоматом развернул правильную конструкцию с уже заполненными параметрами
а что, с public и без public разве это не одно и тоже?
Артём Рыженький, Уважаемый, внимательнее документацию, и почитайте про принцип постановки Барбары Лисков
Евгений Ромашкан, ну я читал, что если писать без public, то по дефолту — public, так что не наезжайте 🙂
вот шторм мне развернул правильный варик, когда я набрал function __construct() — без public
function __construct($route)
вопрос решён, спасибо за участие
на Ваш кстати удалённый вариант шторм ругался, что метод должен быть абстрактным 🙂
Перезапись конструктора родителя в потомке
Пусть у нас есть вот такой класс User , у которого свойства name и age задаются в конструкторе и в дальнейшем доступны только для чтения (то есть приватные и имеют только геттеры, но не сеттеры):
От этого класса наследует класс Student :
Класс-потомок не имеет своего конструктора — это значит что при создании объекта класса сработает конструктор родителя:
Все замечательно, но есть проблема: мы бы хотели при создании объекта класса Student третьим параметром передавать еще и курс, вот так:
Самое простое, что можно сделать, это переопределить конструктор родителя своим конструктором, забрав из родителя его код:
При этом мы в классе потомке обращаемся к приватным свойствам родителя name и age , что, конечно же, не будет работать так, как нам нужно. Переделаем их на protected :
Теперь при создании студента третьим параметром мы можем передать и курс:
Не подсматривая в мой код реализуйте такой же класс Student , наследующий от User .
Используем конструктор родителя
Понятно, что дублирование кода родителя в классе потомке — это не очень хорошо. Давайте вместо дублирования кода в конструкторе потомка вызовем конструктор родителя.
Для полной ясности распишу все по шагам. Вот так выглядит конструктор класса User , он принимает два параметра $name и $age и записывает их в соответствующие свойства:
Вот конструктор класса Student , который мы хотим переписать:
Конструктор родителя можно вызвать внутри потомка с помощью parent . При этом конструктор родителя первым параметром ожидает имя, а вторым — возраст, и мы должны ему их передать, вот так:
Напишем полный код класса Student :
Проверим, что все работает:
getName(); // выведет ‘john’ echo $student->getAge(); // выведет 19 echo $student->getCourse(); // выведет 2 ?>?php>
Так как класс Student теперь не обращается напрямую к свойствам name и age родителя, можно их опять сделать приватными:
Сделайте класс User , в котором будут следующие свойства только для чтения: name и surname . Начальные значения этих свойств должны устанавливаться в конструкторе. Сделайте также геттеры этих свойств.
Модифицируйте предыдущую задачу так, чтобы третьим параметром в конструктор передавалась дата рождения работника в формате год-месяц-день. Запишите ее в свойство birthday . Сделайте геттер для этого свойства.
Модифицируйте предыдущую задачу так, чтобы был приватный метод calculateAge , который параметром будет принимать дату рождения, а возвращать возраст с учетом того, был ли уже день рождения в этом году, или нет.
Модифицируйте предыдущую задачу так, чтобы метод calculateAge вызывался в конструкторе объекта, рассчитывал возраст пользователя и записывал его в приватное свойство age . Сделайте геттер для этого свойства.
Сделайте класс Employee , который будет наследовать от класса User . Пусть новый класс имеет свойство salary , в котором будет хранится зарплата работника. Зарплата должна передаваться четвертым параметром в конструктор объекта. Сделайте также геттер для этого свойства.