Подробный разбор модификаторов доступа
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 39 из 91.
Теперь, когда вы понимаете три модификатора доступа, давайте изучим, как они ведут себя в сценариях наследования. Ключевой момент заключается в том, что члены protected становятся доступными для дочерних классов, в то время как члены private остаются скрытыми даже от дочерних классов.
<?php
class Vehicle {
public $brand;
protected $engineType;
private $serialNumber;
public function __construct($brand, $engine, $serial) {
$this->brand = $brand;
$this->engineType = $engine;
$this->serialNumber = $serial;
}
private function getSerial() {
return $this->serialNumber;
}
protected function getEngineInfo() {
return $this->engineType;
}
}
class Car extends Vehicle {
public function getDetails() {
return $this->brand . " - " . $this->getEngineInfo();
// $this->serialNumber вызовет ошибку — private!
// $this->getSerial() также не сработает — приватный метод!
}
}
$car = new Car("Toyota", "V6", "ABC123");
echo $car->getDetails();
Вывод:
Toyota - V6Класс Car может обращаться к $brand (public) и вызывать getEngineInfo() (protected), но не имеет доступа к $serialNumber или getSerial(), так как они являются приватными (private) для Vehicle. Это различие позволяет делиться некоторыми внутренними деталями с дочерними классами, сохраняя при этом другие полностью скрытыми.
Ключевой момент: Используйте protected, когда дочерним классам нужен доступ к внутренним данным или методам, и private, когда даже дочерние классы не должны касаться определенных деталей реализации.
Задание
ЛегкоДавайте создадим систему управления устройствами, чтобы изучить, как ведут себя модификаторы доступа при наследовании. Вы создадите базовый класс Device со свойствами разных уровней видимости, а затем расширите его классом Smartphone, который продемонстрирует, к каким членам дочерние классы могут и не могут обращаться.
Вы организуете свой код в трех файлах:
Device.php— Создайте классDevice, который представляет электронные устройства с различными уровнями конфиденциальности данных. Включите:publicсвойство$brandдля названия производителяprotectedсвойство$modelNumberдля внутренней идентификацииprivateсвойство$manufacturingCodeдля заводских данных
privateметодgetManufacturingCode(), который возвращает производственный код. ДобавьтеpublicметодgetModelInfo(), который возвращает"Model: [modelNumber]". Наконец, добавьтеpublicметодgetFullCode(), который возвращает"[brand]-[manufacturingCode]"— это демонстрирует, как сам класс может обращаться к своим собственным приватным членам.Smartphone.php— Создайте классSmartphone, который расширяетDevice. Подключите файл Device. Конструктор должен принимать brand, modelNumber, manufacturingCode и название операционной системы. Вызовите родительский конструктор с первыми тремя значениями, затем сохраните ОС в приватном свойстве. Добавьте публичный методgetDeviceDetails(), который возвращает"[brand] [modelNumber] running [os]". Обратите внимание, как вы можете напрямую обращаться к публичному$brandи защищенному$modelNumber, но не можете напрямую обратиться к приватному$manufacturingCode— вместо этого вам нужно будет использовать унаследованный публичный методgetFullCode().main.php— Подключите файл Smartphone. Вы получите четыре входных значения: название бренда, номер модели, производственный код и операционную систему. Создайте экземплярSmartphoneс этими значениями. Выведите три строки:- Результат вызова
getDeviceDetails() - Результат вызова унаследованного метода
getModelInfo() - Результат вызова унаследованного метода
getFullCode()
- Результат вызова
Эта задача подчеркивает ключевое различие: ваш класс Smartphone может свободно использовать защищенное свойство $modelNumber, унаследованное от Device, но приватное свойство $manufacturingCode и метод getManufacturingCode() остаются полностью скрытыми — доступными только через публичный интерфейс, который класс Device решил открыть.
Шпаргалка
В наследовании члены со спецификатором protected доступны дочерним классам, в то время как члены private остаются скрытыми даже от дочерних классов.
<?php
class Vehicle {
public $brand;
protected $engineType;
private $serialNumber;
public function __construct($brand, $engine, $serial) {
$this->brand = $brand;
$this->engineType = $engine;
$this->serialNumber = $serial;
}
private function getSerial() {
return $this->serialNumber;
}
protected function getEngineInfo() {
return $this->engineType;
}
}
class Car extends Vehicle {
public function getDetails() {
return $this->brand . " - " . $this->getEngineInfo();
// $this->serialNumber вызовет ошибку - private!
// $this->getSerial() также не сработает - приватный метод!
}
}
$car = new Car("Toyota", "V6", "ABC123");
echo $car->getDetails(); // Toyota - V6
Дочерние классы могут обращаться к:
publicсвойствам и методамprotectedсвойствам и методам
Дочерние классы не могут обращаться к:
privateсвойствам и методам (они остаются доступными только для родительского класса)
Лучшая практика: Используйте protected, когда дочерним классам нужен доступ к внутренним данным или методам, и private, когда даже дочерние классы не должны иметь доступа к определенным деталям реализации.
Попробуйте сами
<?php
require_once 'Smartphone.php';
// Чтение входных данных
$brand = trim(fgets(STDIN));
$modelNumber = trim(fgets(STDIN));
$manufacturingCode = trim(fgets(STDIN));
$os = trim(fgets(STDIN));
// TODO: Создать экземпляр Smartphone с входными значениями
// TODO: Вывести результат метода getDeviceDetails()
// TODO: Вывести результат унаследованного метода getModelInfo()
// TODO: Вывести результат унаследованного метода getFullCode()
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Итоги — Простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыИтоги — Иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateПодробный разбор модификаторов доступаГеттеры и сеттерыСокрытие данныхConstructor Promotion (8.0)Итоги — Система учета студентов10Продвинутые концепции ООП
Композиция против наследованияВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий2Пространства имен и автозагрузка
Введение в пространства именКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerИтоги: структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс против абстрактного классаType Hinting с интерфейсамиИтоги — Калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeИтоги — Кастомная коллекция11Система типов и обработка ошибок
Объявление типовNullable-типыТипы объединения и пересеченияКлассы исключенийИерархия пользовательских исключенийTry, Catch, FinallyИтоги — Валидатор форм14Проект: Управление библиотекой
Обзор проектаКлассы Book и User3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищенные свойстваСвойства Readonly (PHP 8.1)Итоги — Менеджер банковского счета6Полиморфизм
Снова о переопределении методовПолиморфизм через интерфейсыType Hinting и Union TypesПозднее статическое связываниеИтоги — Payment Processor9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy