Модификаторы доступа 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]Результат:
Дочерний класс также может расширять видимость (protected → public) при переопределении члена, но не сужать её — переопределение публичного метода как 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 обеспечивает инкапсуляцию. При правильном использовании — скрывая детали за небольшим публичным интерфейсом — они делают код более безопасным для изменений и простым для понимания.