W3docs

protected

Ключевое слово protected в PHP объявляет член класса защищённым — он доступен только внутри самого класса и его подклассов.

Ключевое слово protected в PHP

protected — один из трёх модификаторов доступа PHP (наряду с public и private). Он управляет видимостью — кому разрешено читать или вызывать член класса.

Член, объявленный protected, доступен:

  • внутри класса, который его объявляет, и
  • внутри любого класса, который наследует от него (подкласса).

Он недоступен снаружи — то есть из обычного кода, который просто держит объект ($obj->member). Эта «золотая середина» делает protected особенно полезным: он скрывает детали реализации от внешнего мира, одновременно позволяя подклассам опираться на эти детали. Для полного сравнения см. Модификаторы доступа PHP.

На этой странице рассматриваются синтаксис, поведение protected при наследовании, типичные подводные камни и случаи, когда стоит выбирать его вместо private или public.

Синтаксис

Поместите ключевое слово protected перед объявлением свойства или метода:

class MyClass {
  protected $myProtectedProperty;

  protected function myProtectedMethod() {
    // Code here
  }
}

Статический член также можно пометить как protected:

class Config {
  protected static $instances = 0;

  protected static function register() {
    self::$instances++;
  }
}

protected vs private vs public

Три модификатора отличаются только тем, где виден член:

МодификаторТот же классПодклассВнешний код
publicдадада
protectedдаданет
privateданетнет

Ключевое отличие: члены private невидимы даже для подклассов, тогда как члены protected доступны по всей цепочке наследования. Выбирайте protected, когда подклассу действительно нужны данные или вспомогательный метод, но вы всё равно хотите исключить их из публичного API.

Примеры

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

<?php

// Example 1
class Animal
{
  protected $name;

  public function __construct($name)
  {
    $this->name = $name;
  }

  protected function getName()
  {
    return $this->name;
  }
}

class Dog extends Animal
{
  public function bark()
  {
    $name = $this->getName();
    echo "$name barks!" . PHP_EOL;
  }
}

$dog = new Dog("Rufus");
$dog->bark(); // Output: Rufus barks!

// Example 2
class BankAccount
{
  protected $balance = 0;

  public function deposit($amount)
  {
    $this->balance += $amount;
  }

  protected function canWithdraw($amount)
  {
    return $amount <= $this->balance;
  }
}

class SavingsAccount extends BankAccount
{
  public function withdraw($amount)
  {
    if ($this->canWithdraw($amount)) {
      $this->balance -= $amount;
      echo "Withdrawal successful!" . PHP_EOL;
    } else {
      echo "Insufficient funds!" . PHP_EOL;
    }
  }
}

$savingsAccount = new SavingsAccount();
$savingsAccount->deposit(100);
$savingsAccount->withdraw(50); // Output: Withdrawal successful!
$savingsAccount->withdraw(100); // Output: Insufficient funds!

В обоих случаях подкласс (Dog, SavingsAccount) свободно вызывает защищённый член родителя. Данные и вспомогательная логика остаются доступными через наследование, никогда не выходя во внешний код.

Обращение к protected-членам снаружи приводит к ошибке

Как только вы пытаетесь обратиться к защищённому члену из обычного кода, PHP выбрасывает фатальную ошибку:

<?php

class Animal {
  protected $name = "Rufus";
}

$animal = new Animal();
echo $animal->name; // Fatal error: Cannot access protected property Animal::$name

Вот как работает защита — свойство просто не является частью публичного интерфейса объекта.

Подводный камень: подкласс может обратиться к членам объекта того же типа

Распространённый сюрприз: видимость проверяется по классу, а не по конкретному объекту. Объект может обращаться к защищённым членам другого объекта, если оба являются экземплярами одного класса (или связанного класса, которому виден этот член):

<?php

class Wallet {
  protected $balance = 100;

  public function isRicherThan(Wallet $other): bool
  {
    // $other->balance is protected, but we're inside Wallet, so it's allowed
    return $this->balance > $other->balance;
  }
}

$a = new Wallet();
$b = new Wallet();
var_dump($a->isRicherThan($b)); // bool(false)

Когда использовать protected

Используйте protected, когда:

  • Подклассу нужно повторно использовать или переопределить внутреннее состояние или вспомогательные методы, но внешний код не должен иметь к ним доступа.
  • Вы проектируете базовый класс, предназначенный для расширения (см. Абстрактные классы PHP), и хотите предоставить подклассам «строительные блоки» методов.

Предпочтите private, когда даже подклассы не должны зависеть от внутренней детали — это даст вам свободу изменять её впоследствии, не ломая дочерние классы. Используйте public только для намеренного, задокументированного API класса.

Резюме

  • Члены protected видны внутри объявляющего класса и его подклассов, но недоступны внешнему коду.
  • Это «золотая середина» между public (виден везде) и private (виден только в объявляющем классе).
  • Видимость проверяется по классу, поэтому объекты одного типа могут обращаться к защищённым членам друг друга.
  • Используйте его для обмена повторно используемыми внутренними деталями по цепочке наследования, не выставляя их в публичный API.

Для более глубокого изучения продолжите чтение: Наследование PHP, Классы и объекты PHP, а также Статические свойства.

Практика

Практика
В PHP что из перечисленного может обращаться к защищённым свойствам и методам?
В PHP что из перечисленного может обращаться к защищённым свойствам и методам?
Was this page helpful?