PHP Учебник

PHP Старт Введение в PHP Установка PHP Синтаксис PHP Комментарии в PHP Переменные PHP PHP Echo / Print Типы данных PHP Строки PHP Числа PHP Математика в PHP Константы PHP Операторы PHP PHP If...Else...Elseif PHP Switch Циклы в PHP Функции PHP Массивы PHP PHP Суперглобальные PHP RegEx

PHP Формы

Обработка форм PHP Валидация форм PHP Обязательные поля Валидация URL/E-mail Полная форма PHP

PHP Продвинутый

PHP Дата и время PHP Include/Require PHP Работа с файлами Открытие/Чтение файлов Создание/Запись файлов PHP Загрузка файлов Файлы cookie PHP Сессии PHP Фильтры PHP Расширенные фильтры PHP Функция Callback PHP JSON PHP Исключения

PHP OOP

Что такое ООП в PHP Классы/Объекты PHP Цепочки методов PHP Конструктор PHP Деструктор PHP Модификаторы доступа Наследование в PHP Константы класса PHP Подсказка типов PHP Подсказка интерфейсов Абстрактные классы PHP PHP Интерфейсы PHP Полиформизм PHP Трейты Статические методы PHP Статические свойства PHP Пространства имен PHP Итерируемые объекты

База данных MySQL

База данных MySQL Подключение к MySQL Создание БД MySQL Создание таблицы MySQL Вставка данных MySQL Получить ID MySQL Подготовленные операторы PHP MySQL Получение данных MySQL Предложение WHERE Предложение ORDER BY Обновление данных MySQL Удаление данных БД MySQL Limit Data

PHP XML

Парсеры PHP XML Парсер PHP SimpleXML Получить PHP SimpleXML PHP XML Expat PHP XML DOM

PHP - AJAX

AJAX Введение AJAX PHP AJAX База Данных AJAX XML AJAX Живой поиск AJAX Опрос

PHP Примеры

PHP Примеры Практика ООП PHP PHP квиз-тест Упражнения Базовый PHP Упражнения Алгоритмы Упражнения Массивы Упражнения Цикл for Упражнения Функции Регулярные выражения Упражнения Дата PHP Упражнения Строки PHP Математика PHP Упражнения Формы PHP Упражнения Классы PHP Упражнения JSON PHP PHP Задачник


Наследование в объектно-ориентированном программировании PHP




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


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

Эту связь обычно описывают с помощью терминов "родительский" и "дочерний". Класс, от которого мы наследуем, называется базовым классом, суперклассом или родительским классом. Класс, который наследует функциональность, называется подклассом или дочерним классом. В наследовании у нас есть родительский класс со своими собственными методами и свойствами, а также дочерний класс (или классы), которые унаследуют все общедоступные и защищенные свойства и методы родительского класса. Кроме того, у них могут быть свои свойства и методы.

Используя наследование, мы можем создать повторно используемый фрагмент кода, который мы пишем только один раз в родительском классе и используем снова столько, сколько нам нужно в дочерних классах.

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

В PHP мы используем ключевое слово extends, чтобы указать, что класс наследуется от другого класса.

Синтаксис

<?php
class ParentClass {

}
class ChildClass extends ParentClass {

}
?>

В приведенном ниже примере класс SportsCar наследует класс Car, поэтому у него есть доступ ко всем методам и свойствам Car, которые не являются приватными. Это позволяет нам писать общедоступные методы setModel() и hello() только один раз в родительском классе, а затем использовать эти методы как в родительском, так и в дочернем классах:

<?php
//Родительский класс
class Car {
  // Приватное свойство внутри класса
  private $model;
 
  //Публичный метод установки
  public function setModel($model) {
    $this -> model = $model;
  }
 
  public function hello() {
    return "Бип! Я <i>" . $this -> model . "</i><br />";
  }
}
 
//Дочерний класс наследует код родительского класса
class SportsCar extends Car {
  //Нет кода в дочернем классе
}
 
//Создаем экземпляр из дочернего класса
$sportsCar1 = new SportsCar();
  
// Устанавливаем значение свойства класса
// Для этого мы используем метод, который мы создали в родительском
$sportsCar1 -> setModel('Mercedes Benz');
  
//Используем второй метод, который дочерний класс унаследовал от родительского класса
echo $sportsCar1 -> hello();
?>

Результат выполнения кода:

Бип! Я Mercedes Benz

Так же, как дочерний класс может использовать свойства и методы своего родительского класса, он также может иметь собственные свойства и методы. Однако, хотя дочерний класс может использовать код, унаследованный от родительского, родительскому классу не разрешается использовать код дочернего класса.

В приведенном ниже примере мы добавим в дочерний класс некоторый собственный код, добавив свойство $style, а также метод driveItWithStyle():

<?php
class Car {  
  //Приватное свойство или метод может использовать только родитель
  private $model;  
  // Публичные методы и свойства могут использоваться как родительским, так и дочерним классами
  public function setModel($model) {
    $this -> model = $model;
  }   
  public function getModel() {
    return $this -> model;
  }
}
  
// Дочерний класс может использовать код, унаследованный от родительского класса, 
// а также может иметь собственный код
class SportsCar extends Car { 
  private $style = 'быстрый и надёжный'; 
  public function driveItWithStyle() {
    return 'Автомобиль '  . $this -> getModel() . ' ' . $this -> style . '';
  }
}
 
//создать экземпляр из дочернего класса
$sportsCar1 = new SportsCar();
   
// Используем метод, который дочерний класс унаследовал от родительского класса
$sportsCar1 -> setModel('Ferrari');
  
// Используем метод, который был добавлен в дочерний класс
echo $sportsCar1 -> driveItWithStyle();
?>

Результат выполнения кода:

Автомобиль Ferrari быстрый и надёжный

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

В этом уроке мы узнаем о третьем модификаторе — protected, который позволяет использовать код как внутри класса, так и из его дочерних классов.

Как вы думаете, что может случиться, когда мы попытаемся вызвать приватный метод или свойство извне класса?

Следующий пример демонстрирует, что может произойти, если мы объявляем свойство $model в родительском элементе приватным, но все же пытаемся получить к нему доступ из его дочернего класса:

<?php
class Car {
  // Свойство $model является приватным, поэтому к нему можно получить доступ
  // только изнутри класса
  private $model;  
  //Публичный метод установки
  public function setModel($model) {
    $this -> model = $model;
  }
}
   
// Дочерний класс
class SportsCar extends Car {
  //Пытаемся получить доступ к приватному свойству model
  public function hello() {
    return "Бип! Я <i>" . $this -> model . "</i><br />";
  }
}
   
//Создаём экземпляр из дочернего класса
$sportsCar1 = new SportsCar();
  
//Устанавливаем имя модели класса
$sportsCar1 -> setModel('Mercedes Benz');
   
//Получаем значение свойства model 
echo $sportsCar1 -> hello();
?>

Результат выполнения кода:

Бип! Я

Мы не вывели значение модели автомобиля $model, потому что метод hello() в дочернем классе пытается получить доступ к приватному свойству $model, которое принадлежит родительскому классу.

Мы можем решить эту проблему, объявив свойство $model в родительском классе как защищенное protected, а не приватное, потому что, когда мы объявляем свойство или метод как защищенные, мы можем обращаться к нему как из родительского, так и из дочернего классов:

<?php
class Car {
  // Свойство $model теперь защищено, поэтому к нему можно получить доступ
  // из класса и его дочерних классов
  protected $model;
  public function setModel($model) {
    $this -> model = $model;
  }
}
  
class SportsCar extends Car {
  // Теперь есть доступ к защищенному свойству, принадлежащему родителю
  public function hello() {
    return "Бип! Я <i>" . $this -> model . "</i><br />";
  }
}
  
//Создаём экземпляр из дочернего класса
$sportsCar1 = new SportsCar();
  
//Задаём имя модели класса
$sportsCar1 -> setModel('Mercedes Benz');
  
//Получаем имя модели класса
echo $sportsCar1 -> hello();
?>

Результат выполнения кода:

Бип! Я Mercedes Benz

Сказанное выше относится и к методам:

<?php
class Car {
  public $name;
  public $color;
  public function __construct($name, $color) {
    $this->name = $name;
    $this->color = $color;
  }
  protected function intro() {
    echo "Автомобиль {$this->name} имеет цвет: {$this->color}.";
  }
}
  
class SportsCar extends Car {  
  public function message() {
    echo "Какой цвет у автомобиля? " . "<br>";
    // доступ к защищенному методу, принадлежащему родителю
    $this -> intro();
  }
}
  
//Создаём экземпляр из дочернего класса
$sportsCar1 = new SportsCar('Mercedes Benz', 'Красный');  
$sportsCar1 -> message();
?>

Результат выполнения кода:

Какой цвет у автомобиля?
Автомобиль Mercedes Benz имеет цвет: Красный.

Публичный метод message() дочернего класса SportsCar имеет доступ к методу intro() (который защищен) родительского класса.

Так же, как дочерний класс может иметь свои собственные свойства и методы, он может переопределять свойства и методы родительского класса. Когда мы переопределяем свойства и методы класса, мы переписываем метод или свойство (с использованием того же имени), которое существует в родительском элементе, снова в дочернем, но присваиваем ему другое значение или код.

Посмотрите на пример ниже. Методы __construct() и intro() в дочернем классе (SportsCar) переопределят методы __construct() и intro() в родительском классе (Car):

<?php
class Car {
  public $name;
  public $color;
  public function __construct($name, $color) {
    $this->name = $name;
    $this->color = $color;
  }
   public function intro() {
    echo "Автомобиль {$this->name} имеет цвет: {$this->color}.";
  }
}
  
class SportsCar extends Car { 
  public $weight;
  public function __construct($name, $color, $weight) {
    $this->name = $name;
    $this->color = $color;
    $this->weight = $weight;
  }
  public function intro() {
    echo "Автомобиль {$this->name} имеет цвет {$this->color}, а его вес {$this->weight} кг.";
  }
}
  
$sportsCar1 = new SportsCar('Mercedes Benz', 'Красный', 1800);  
$sportsCar1 -> intro();
?>

Результат выполнения кода:

Автомобиль Mercedes Benz имеет цвет Красный, а его вес 1800 кг.

Ключевое слово final может быть использовано для предотвращения наследования класса или для предотвращения переопределения метода.

В приведенном ниже примере мы объявляем класс Car как final, чтобы предотвратить наследование класса, но все же пытаемся его наследовать. В результате мы получим ошибку:

<?php
final class Car {
  // какой-то код
}

// приведет к ошибке
class SportsCar extends Car {
  // какой-то код
}
?>

Результат выполнения кода:

Fatal error: Class SportsCar may not inherit from final class (Car)

В следующем примере ключевое слово final испольуется для предотвращения переопределение метода:

<?php
class Car {
  final public function intro() {
  // какой-то код
  }
}

class SportsCar extends Car {
  public function intro() { // приведет к ошибке
    // какой-то код
  }  
}
?>

Результат выполнения кода:

Fatal error: Cannot override final method Car::intro()

Попытка переопределить родительский метод intro(), защищенный ключевым словом final, привела к ошибке.

Мы используем наследование, чтобы уменьшить дублирование кода за счет использования кода из родительского класса в дочерних классах. В этом уроке мы изучили один из принципов объектно-ориентированного программирования — концепцию наследования. Мы используем наследование, чтобы уменьшить дублирование кода, используя код родительского класса в дочерних классах. Щелкните здесь, чтобы попрактиковаться в предмете.