W3docs

Модификаторы доступа PHP OOP: исчерпывающее руководство

Модификаторы доступа в PHP (public, protected, private) — основа инкапсуляции в ООП. Узнайте, как управлять видимостью свойств и методов класса.

Модификаторы доступа (их также называют ключевыми словами видимости) определяют, кому разрешено читать, изменять или вызывать член класса. Именно они реализуют механизм инкапсуляции — одной из ключевых идей объектно-ориентированного программирования: вы открываете небольшой, безопасный публичный интерфейс и скрываете внутренние детали, которых вызывающий код не должен касаться.

В этой главе рассматриваются три ключевых слова видимости PHP — public, protected и private — что каждое из них разрешает, что происходит при нарушении правил, как видимость работает при наследовании, а также распространённые паттерны (геттеры, сеттеры и продвижение свойств в конструкторе), которые их используют. Если классы для вас в новинку, сначала прочитайте PHP Классы и объекты.

Три модификатора доступа вкратце

МодификаторВнутри того же классаВ дочернем классеСнаружи (например, $obj->member)
public
protected
private

Модификатор можно применять к свойствам, методам и константам класса. Если модификатор у метода не указан, PHP по умолчанию считает его public; для свойства модификатор необходимо указывать явно (старое ключевое слово var является псевдонимом public).

Модификатор доступа public

public — наиболее разрешительный уровень. Публичный член доступен откуда угодно — внутри класса, из дочерних классов и из любого кода, удерживающего объект. Используйте его для предназначенного интерфейса вашего класса: методов, которые вызывающий код должен использовать.

<?php
class User {
  public $name;

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

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

$user = new User();
$user->setName("Ada");      // calling a public method
echo $user->getName();      // Ada
echo "\n";
$user->name = "Grace";      // touching a public property directly
echo $user->name;           // Grace

Результат:

Ada
Grace

Поскольку $name является публичным, вызывающий код может изменить его напрямую через $user->name = ..., минуя setName(). Именно поэтому публичные свойства зачастую не рекомендуются: вы теряете возможность проверять значение. Пометив свойство как protected или private и открыв к нему доступ через методы, вы возвращаете этот контроль.

Модификатор доступа protected

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

<?php
class User {
  protected $email;

  protected function setEmail($email) {
    $this->email = $email;
  }

  public function getEmail() {
    return $this->email;
  }
}

$user = new User();
echo $user->getEmail();   // works: getEmail() is public
$user->setEmail("[email protected]"); // Fatal error: Call to protected method User::setEmail()

При выполнении первая строка ничего не выводит (email по-прежнему null), после чего выполнение прерывается с ошибкой:

PHP Fatal error:  Uncaught Error: Call to protected method User::setEmail() from global scope

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

Модификатор доступа private

private — наиболее ограничительный уровень. Член виден только внутри класса, в котором он объявлен — даже подклассы не могут его видеть. Используйте private, когда деталь является сугубо внутренней и может измениться в любой момент — например, хэш пароля или кэшированное вычисление.

<?php
class User {
  private $password;

  public function setPassword($password) {
    // hide the real value behind validation
    $this->password = password_hash($password, PASSWORD_DEFAULT);
  }

  public function check($attempt) {
    return password_verify($attempt, $this->password);
  }
}

$user = new User();
$user->setPassword("s3cret");
var_dump($user->check("s3cret"));  // bool(true)
var_dump($user->check("wrong"));   // bool(false)

Результат:

bool(true)
bool(false)

Попытка прочитать $user->password снаружи класса вызовет Error: Cannot access private property User::$password. Вызывающий код может взаимодействовать только через публичные методы setPassword() и check() — сырой хэш надёжно скрыт.

Модификаторы доступа и наследование

Когда дочерний класс расширяет родительский, он наследует его члены вместе с их видимостью. Члены с модификаторами public и protected доступны внутри дочернего класса; члены с private дочернему классу вообще не видны.

<?php
class User {
  protected $email;

  protected function setEmail($email) {
    $this->email = $email;
  }

  public function getEmail() {
    return $this->email;
  }
}

class Admin extends User {
  // Admin can call the protected setEmail() because it is a subclass
  public function updateEmail($email) {
    $this->setEmail($email);
  }
}

$admin = new Admin();
$admin->updateEmail("[email protected]");
echo $admin->getEmail();   // [email protected]

Результат:

[email protected]

Дочерний класс также может расширять видимость (protectedpublic) при переопределении члена, но не сужать её — переопределение публичного метода как private вызывает фатальную ошибку. Подробнее о построении иерархий классов см. в PHP Наследование.

Видимость констант и продвижение свойств в конструкторе

Константы класса принимают те же модификаторы (начиная с PHP 7.1). Это позволяет открывать одни константы, скрывая при этом служебные значения:

<?php
class Order {
  public const STATUS_PAID = "paid";
  private const TAX_RATE = 0.2;   // internal detail

  public function total(float $net): float {
    return $net * (1 + self::TAX_RATE);
  }
}

echo Order::STATUS_PAID;            // paid
echo "\n";
echo (new Order())->total(100);    // 120

Результат:

paid
120

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

<?php
class Point {
  public function __construct(
    public int $x = 0,
    private int $y = 0,   // declared, assigned, and made private in one line
  ) {}

  public function describe(): string {
    return "x={$this->x}, y={$this->y}";
  }
}

echo (new Point(3, 4))->describe();  // x=3, y=4

Результат:

x=3, y=4

Полное описание этих возможностей см. в Константы класса PHP и Конструктор PHP.

Выбор правильного модификатора

  • Начинайте с наиболее ограничительного уровня (private) и ослабляйте его только при реальной необходимости. Это делает ваш публичный API небольшим и удобным для изменения в будущем.
  • Делайте член public, если он является частью интерфейса, на который полагается вызывающий код.
  • Делайте его protected, если он нужен подклассам — но не внешнему коду.
  • Делайте его private, если это деталь реализации, которая может измениться без предупреждения.
  • Предпочитайте приватные/защищённые свойства с публичными методами геттеров/сеттеров вместо публичных свойств, чтобы сохранять контроль над тем, как значения читаются и записываются. Эта идея является частью того, что такое ООП.

Резюме

Модификаторы доступа управляют видимостью членов класса: public открывает доступ откуда угодно, protected — из класса и его подклассов, private — только из объявляющего класса. Они применяются к свойствам, методам и константам и являются механизмом, с помощью которого PHP обеспечивает инкапсуляцию. При правильном использовании — скрывая детали за небольшим публичным интерфейсом — они делают код более безопасным для изменений и простым для понимания.

Практика

Практика
Что такое модификаторы доступа в PHP и что они делают?
Что такое модификаторы доступа в PHP и что они делают?
Was this page helpful?