Menu
Coddy logo textTech

Подробный разбор модификаторов доступа

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

challenge icon

Задание

Легко

Давайте создадим систему управления устройствами, чтобы изучить, как ведут себя модификаторы доступа при наследовании. Вы создадите базовый класс 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()
?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование