Полный цикл в digital

Наследование extends

Наследование является одним из основных аспектов объектно-ориентированного программирования. Наследование позволяет классу взять функционал уже имеющихся классов и при необходимости переопределить его. Если у нас есть какой-нибудь класс, в котором не хватает пары функций, то гораздо проще переопределить имеющийся класс, написав пару строк, чем создавать новый с нуля, переписывая кучу кода.

Чтобы наследовать один класс от другого, нам надо применить оператор extends. Стоит отметить, что в PHP мы можем унаследовать класс только от одного класса. Множественное наследование не поддерживается.

Например, унаследуем класс Employee от класса Person:

<?
class Person
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
    function displayInfo()
    {
        echo "Имя: $this->name<br>";
    }
}
class Employee extends Person {}
$tom = new Employee("Tom");
$tom->displayInfo();

В данном случае предположим, что класс Person представляет человека в целом, а класс Employee - работника некого предприятия. В этой связи каждый работник преддставляет человека. И чтобы не дублировать один и тот же функционал, лучше в данном случае унаследовать класс работника - Employee от класа человека - Person. В этой паре класс Person еще называется родительским или базовым классом, а класс - Employee - производным классом или классом-наследником.

И так как класс Employee унаследован от Person, для объектов класса Employee мы можем использовать функционал родительского класса Person. Так, для создания объекта Employee в данном случае вызывается конструктор, который определен в классе Person и который в качестве параметра принимает имя человека:

$tom = new Employee("Tom");

И также у переменной типа Employee вызывается метод displayInfo, который определен в классе Person:

$tom -> displayInfo();

Переопределение функционала

Унаследовав функционал от родительского класса класс-наследник может добавить свои свойства и методы или переопредилить унаследованный функционал. Например, изменим класс Employee, добавив в него данные о компании, где работает работник:

<?
class Person
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
    function displayInfo()
    {
        echo "Имя: $this->name<br>";
    }
}
class Employee extends Person
{
    public $company;
    function __construct($name, $company)
    {
        $this->name = $name;
        $this->company = $company;
    }
    function displayInfo()
    {
        echo "Имя: $this->name<br>";
        echo "Работает в $this->company<br>";
    }
}
$tom = new Employee("Tom", "Microsoft");
$tom->displayInfo();

Здесь класс Employee добавляет новое свойство - $company, которое хранит компанию работника. Также класс Employee переопределил конструктор, в который пеередаются данные для имени и компании. А также переопределен метод displayInfo(). Соответственно для создания объекта класса Employee, теперь необходимо использовать переопределенный в классе Employee конструктор:

$tom = new Employee("Tom", "Microsoft");

Класс-наследник переопределяет конструктор родительского класса, то для создания объекта класса-наследника необходимо использовать переопределенный в нем конструктор.

И также изменится поведение метода displayInfo(), который кроме имени также выведет и компанию работника:

Имя: Tom
Работает в Microsoft

Вызов функционала родительского класса

Если мы посмотрим на код класса-наследника Employee, то можем увидеть части кода, которые повторяют код класса Person. Например, установка имени в конструкторе:

$this->name = $name;

Также вывод имени работника в методе displayInfo():

echo "Имя: $this->name<br>";

В обоих случаях речь идет об одной строке кода. Однако что, если конструктор Employee повторяет установку не одного, а десятка свойств. Соответственно что, если метод displayInfo в классе-наследнике повторяет горадо больше действий родительского класса. В этом случае горадо рациональнее не писать повторяющийся код в классе-наследнике, а вызвать в нем соответствующий функционал родительского класса.

Если нам надо обратиться к методу родительского класса, то мы можем использовать ключевое слово parent, после которого используется двойное двоеточие :: и затем вызываемый метод. Например, перепишем предыдущий пример:

<?
class Person
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
    function displayInfo()
    {
        echo "Имя: $this->name<br>";
    }
}
class Employee extends Person
{
    public $company;
    function __construct($name, $company)
    {
        parent::__construct($name);
        $this->company = $company;
    }
    function displayInfo()
    {
        parent::displayInfo();
        echo "Работает в $this->company<br>";
    }
}
$tom = new Employee("Tom", "Microsoft");
$tom->displayInfo();

Теперь в конструкторе Employee вызывается конструктор базового класса:

parent::__construct($name);

В нем собственно и происходит установка имени. И подобным образом в методе displayInfo() вызывается реализация метода класса Person:

parent::displayInfo();

В итоге мы получим тот же самый результат. Стоит отметить, что в реальности ключевое слово parent заменяет название класса. То есть мы также могли вызывать функционал родительского класса через имя этого класса:

<?
class Employee extends Person
{
    public $company;
    function __construct($name, $company)
    {
        Person::__construct($name);
        $this->company = $company;
    }
    function displayInfo()
    {
        Person::displayInfo();
        echo "Работает в $this->company<br>";
    }
}

Оператор instanceof

Оператор instanceof позволяет проверить принадлежность объекта определенному класса. Слева от оператора располагается объект, котоый надо проверить, а справа - название класса. И если объект представляет класс, то оператор возвращает true. Например:

<?
class Person
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
    function displayInfo()
    {
        echo "Имя: $this->name<br>";
    }
}
class Employee extends Person
{
    public $company;
    function __construct($name, $company)
    {
        Person::__construct($name);
        $this->company = $company;
    }
    function displayInfo()
    {
        Person::displayInfo();
        echo "Работает в $this->company<br>";
    }
}
class Manager {}
$tom = new Employee("Tom", "Microsoft");
// true
$tom instanceof Employee; 
// true
$tom instanceof Person; 
// false
$tom instanceof Manager; 

Здесь переменная $tom представляет класс Employee, поэтому $tom instanceof Employee возвращает true.

Так как класс Employee унаследован от Person, то переменная $tom также представляет класс Person (работник также является человеком).

А вот класс Manager переменная $tom не преддставляет, поэтому выражение $tom instanceof Manager возвращает false.

Запрет наследования и оператор final

В примере выше метод displayInfo() переопределялся классом-наследником. Однако иногда возникают ситуации, когда надо запретить переопределение методов. Для этого в классе-родителе надо указать методы с модификатором final:

<?
class Person
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
    final function displayInfo()
    {
        echo "Имя: $this->name<br>";
    }
}
class Employee extends Person
{
    public $company;
    function __construct($name, $company)
    {
        Person::__construct($name);
        $this->company = $company;
    }
    function displayEmployeeInfo()
    {
        Person::displayInfo();
        echo "Работает в $this->company<br>";
    }
}
$tom = new Employee("Tom", "Microsoft");
$tom->displayEmployeeInfo();

В этом случае во всех классах-наследниках от класса Person мы уже не сможем определить метод с таким же именем. Поэтому в данном случае в классе Employee определен новый метод - displayEmployeeInfo.

Также мы можем вообще запретить наследование от класса. Для этого данный класс надо определить с модификатором final:

<?
final class Person
{
    public $name;
    function __construct($name)
    {
        $this->name = $name;
    }
    final function displayInfo()
    {
        echo "Имя: $this->name<br>";
    }
}

Теперь мы не сможем унаследовать класс Employee (да и никакой другой класс) от класса Person.

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг