Область видимости свойства, метода или начиная c PHP 7.1.0 константы определяют
путём добавления перед объявлением ключевого слова: public
,
protected
или private
. Доступ к общедоступным членам класса,
— которые объявили с ключевым словом public, — разрешается из любой области видимости.
Доступ к защищённым членам класса, которые объявили с ключевым словом protected, — возможен только
внутри самого класса, и в производных классах-наследниках или родительских классах.
Доступ к закрытым членам класса, — которые объявили с ключевым словом private, — открывается
только для самого класса, в котором их определили.
Свойства класса разрешается определять как открытые — public, защищённые — protected или закрытые — private. Свойства, которые объявили без явного ключевого слова области видимости, определяются как открытые, как будто свойство объявили с ключевым словом public.
Пример #1 Объявление свойства класса
<?php
/**
* Определение класса MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Работает
echo $obj->protected; // Фатальная ошибка
echo $obj->private; // Фатальная ошибка
$obj->printHello(); // Выводит 'Public', 'Protected' и 'Private'
/**
* Определение MyClass2
*/
class MyClass2 extends MyClass
{
// Разрешается переопределять открытые и защищённые свойства, но не закрытые
public $public = 'Public2';
protected $protected = 'Protected2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // Работает
echo $obj2->protected; // Фатальная ошибка
echo $obj2->private; // Предупреждение о неопределённом свойстве
$obj2->printHello(); // Выводит 'Public2', 'Protected2' и предупреждение о неопределённом свойстве
?>
Начиная с PHP 8.4 область видимости свойств разрешили также устанавливать асимметрично —
отдельно для чтения и записи. Видимость свойства для записи определяют инструкцией
(set)
, которую указывают сразу после модификатора видимости,
тогда как инструкцию (get)
после модификатора видимости для чтения не указывают, а подразумевают.
Область видимости set
разрешается указывать отдельно,
если только она не слабее области видимости по умолчанию.
Пример #2 Пример асимметричной установки области видимости свойств
<?php
class Book
{
public function __construct(
public private(set) string $title,
public protected(set) string $author,
protected private(set) int $pubYear,
) {}
}
class SpecialBook extends Book
{
public function update(string $author, int $year): void
{
$this->author = $author; // Всё хорошо
$this->pubYear = $year; // Критическая ошибка
}
}
$b = new Book('How to PHP', 'Peter H. Peterson', 2024);
echo $b->title; // Всё хорошо
echo $b->author; // Всё хорошо
echo $b->pubYear; // Критическая ошибка
$b->title = 'How not to PHP'; // Критическая ошибка
$b->author = 'Pedro H. Peterson'; // Критическая ошибка
$b->pubYear = 2023; // Критическая ошибка
?>
Относительно асимметричной области видимости определили ряд условий:
set
разрешается устанавливать только типизированным свойствам.
set
должно быть как у области видимости get
или сильнее. Так, сочетания модификаторов public protected(set)
и protected protected(set)
разрешаются, но более слабое условие области видимости для записи наподобие protected public(set)
вызовет синтаксическую ошибку.
public
.
Поэтому определения public private(set)
и private(set)
установят свойству одни и те же области видимости.
private(set)
автоматически становится окончательным (final
)
и его нельзя повторно объявить в дочернем классе.
set
, а не get
.
Это связано с тем, что ссылка разрешает изменять значение свойства.
get
,
так и операцию записи — set
, и поэтому подчинится области видимости set
,
поскольку ограничение области видимости для записи сильнее.
Замечание: Пробелы в объявлении области видимости для записи не допускаются. Правильно:
private(set)
. Неправильно и вызовет ошибку синтаксического анализа:private( set )
.
При наследовании класса дочернему классу доступно переопределение свойств родительского класса,
которые не обозначили окончательными ключевым словом final
.
При этом дочернему классу разрешается ослабить либо основную видимость — для чтения, либо видимость set
,
если только новая видимость останется такой же или станет слабее, чем у родительского класса.
Однако имейте в виду, что при переопределении свойства с модификатором private
новая область видимости не изменяет видимость родительского свойства, а создаёт новое свойство с другим внутренним именем.
Пример #3 Наследование свойств с асимметричной областью видимости
<?php
class Book
{
protected string $title;
public protected(set) string $author;
protected private(set) int $pubYear;
}
class SpecialBook extends Book
{
public protected(set) $title; // Всё хорошо, поскольку ограничение на чтение слабее, а на запись – такое же
public string $author; // Всё хорошо, поскольку ограничение на чтение такое же, а на запись – слабее
public protected(set) int $pubYear; // Критическая ошибка. Свойства с видимостью private(set) — окончательны!
}
?>
Методы класса разрешается определять как открытые — public, защищённые — protected или закрытые — private. Методы, которые объявили без явного ключевого слова области видимости, определяются как открытые, как будто метод объявили с ключевым словом public.
Пример #4 Объявление метода
<?php
/**
* Определение класса MyClass
*/
class MyClass
{
// Объявление общедоступного конструктора
public function __construct() {}
// Объявление общедоступного метода
public function MyPublic() {}
// Объявление защищённого метода
protected function MyProtected() {}
// Объявление закрытого метода
private function MyPrivate() {}
// Это общедоступный метод
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass();
$myclass->MyPublic(); // Работает
$myclass->MyProtected(); // Фатальная ошибка
$myclass->MyPrivate(); // Фатальная ошибка
$myclass->Foo(); // Общедоступный, защищённый и закрытый методы работают
/**
* Определение класса MyClass2
*/
class MyClass2 extends MyClass
{
// Это общедоступный метод
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Фатальная ошибка
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Работает
$myclass2->Foo2(); // Общедоступный и защищённый методы работают, закрытый — не работает
class Bar
{
public function test()
{
$this->testPrivate();
$this->testPublic();
}
public function testPublic()
{
echo "Bar::testPublic\n";
}
private function testPrivate()
{
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic()
{
echo "Foo::testPublic\n";
}
private function testPrivate()
{
echo "Foo::testPrivate\n";
}
}
$myFoo = new Foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
?>
Начиная с PHP 7.1.0 константы класса разрешается определять как открытые — public, защищённые — protected или закрытые — private. Константы, которые объявили без явного ключевого слова области видимости, определяются как открытые, как будто константу объявили с ключевым словом public.
Пример #5 Пример объявления констант с PHP 7.1.0
<?php
/**
* Объявление класса MyClass
*/
class MyClass
{
// Объявление общедоступной константы
public const MY_PUBLIC = 'public';
// Объявление защищённой константы
protected const MY_PROTECTED = 'protected';
// Объявление закрытой константы
private const MY_PRIVATE = 'private';
public function foo()
{
echo self::MY_PUBLIC;
echo self::MY_PROTECTED;
echo self::MY_PRIVATE;
}
}
$myclass = new MyClass();
MyClass::MY_PUBLIC; // Работает
MyClass::MY_PROTECTED; // Фатальная ошибка
MyClass::MY_PRIVATE; // Фатальная ошибка
$myclass->foo(); // Выводятся константы с модификаторами public, protected и private
/**
* Объявление класса MyClass2
*/
class MyClass2 extends MyClass
{
// Публичный метод
function foo2()
{
echo self::MY_PUBLIC;
echo self::MY_PROTECTED;
echo self::MY_PRIVATE; // Фатальная ошибка
}
}
$myclass2 = new MyClass2;
echo MyClass2::MY_PUBLIC; // Работает
$myclass2->foo2(); // Выводятся константы с модификаторами public и protected, но не с модификатором private
?>
Объектам одного и того же типа доступны защищённые и закрытые члены друг друга, даже если это разные экземпляры. Это связано с тем, что внутри таких объектов уже известны конкретные детали реализации.
Пример #6 Доступ к закрытым членам объекта того же типа
<?php
class Test
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
private function bar()
{
echo 'Доступ к закрытому методу.';
}
public function baz(Test $other)
{
// Закрытое свойство доступно для изменения:
$other->foo = 'привет';
var_dump($other->foo);
// Закрытый метод также доступен для вызова:
$other->bar();
}
}
$test = new Test('test');
$test->baz(new Test('other'));
?>
Результат выполнения приведённого примера:
string(6) "привет" Доступ к закрытому методу.