Видимість і асиметрична видимість · PHP Manual
Видимість властивості, методу або (починаючи з PHP 7.1.0) константи задається ключовим словом public, protected чи private перед оголошенням. Члени класу, оголошені як public, доступні звідусіль. Члени, оголошені як protected, доступні лише всередині самого класу, а також у похідних і батьківських класах. Члени, оголошені як private, доступні лише класу, який їх визначає.
Видимість властивостей
Властивості класу можуть бути оголошені як public, private або protected. Властивості, оголошені без явного ключового слова видимості, вважаються public.
Приклад: Оголошення властивості
<?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; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Виводить Public, Protected і Private
/**
* Визначаємо MyClass2
*/
class MyClass2 extends MyClass
{
// Ми можемо перевизначити public- і protected-властивості, але не private
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; // Fatal Error
echo $obj2->private; // Не визначено
$obj2->printHello(); // Виводить Public2, Protected2, Undefined
?>
Асиметрична видимість властивостей
Починаючи з PHP 8.4, властивостям обʼєкта можна задати видимість асиметрично, з різною областю для читання (get) і запису (set). Видимість set вказується окремо за умови, що вона не дозволяє більше, ніж основна видимість.
Приклад: Асиметрична видимість властивостей
<?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; // OK
$this->pubYear = $year; // Fatal Error
}
}
$b = new Book('How to PHP', 'Peter H. Peterson', 2024);
echo $b->title; // Працює
echo $b->author; // Працює
echo $b->pubYear; // Fatal Error
$b->title = 'How not to PHP'; // Fatal Error
$b->author = 'Pedro H. Peterson'; // Fatal Error
$b->pubYear = 2023; // Fatal Error
?>
Починаючи з PHP 8.5, видимість set можна застосовувати також до статичних властивостей класів.
Приклад: Асиметрична видимість статичної властивості
<?php
class Manager
{
public private(set) static int $calls = 0;
public function doAThing(): string
{
self::$calls++;
// Робимо щось іще.
return "some string";
}
}
$m = new Manager();
$m->doAThing(); // Працює
echo Manager::$calls; // Працює
Manager::$calls = 5; // Fatal error
?>
Результат виконання наведеного прикладу:
1
Fatal error: Uncaught Error: Cannot modify private(set) property Manager::$calls from global scope in /some/file.php
Щодо асиметричної видимості є кілька застережень:
- Окрему видимість
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, бо вона завжди суворіша.
Пробіли в оголошенні set-видимості не дозволені.
private(set)- правильно.private( set )- неправильно й призведе до помилки розбору.
Коли клас успадковує інший, дочірній клас може перевизначити будь-яку властивість, яка не є final. При цьому він може розширити або основну видимість, або видимість set, за умови що нова видимість така сама чи ширша за батьківську. Утім врахуйте: якщо перевизначається private-властивість, батьківська властивість насправді не змінюється, а створюється нова властивість з іншим внутрішнім імʼям.
Приклад: Успадкування асиметричних властивостей
<?php
class Book
{
protected string $title;
public protected(set) string $author;
protected private(set) int $pubYear;
}
class SpecialBook extends Book
{
public protected(set) string $title; // OK, бо читання ширше, а запис такий самий.
public string $author; // OK, бо читання таке саме, а запис ширший.
public protected(set) int $pubYear; // Fatal Error. Властивості private(set) є final.
}
?>
Видимість методів
Методи класу можуть бути оголошені як public, private або protected. Методи, оголошені без явного ключового слова видимості, вважаються public.
Приклад: Оголошення методу
<?php
/**
* Визначаємо MyClass
*/
class MyClass
{
// Оголошуємо публічний конструктор
public function __construct() { }
// Оголошуємо публічний метод
public function MyPublic() { }
// Оголошуємо protected-метод
protected function MyProtected() { }
// Оголошуємо private-метод
private function MyPrivate() { }
// Цей метод публічний
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // Працює
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate(); // Fatal Error
$myclass->Foo(); // Public, Protected і Private працюють
/**
* Визначаємо MyClass2
*/
class MyClass2 extends MyClass
{
// Цей метод публічний
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Fatal Error
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Працює
$myclass2->Foo2(); // Public і Protected працюють, Private - ні
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, private або protected. Константи, оголошені без явного ключового слова видимості, вважаються public.
Приклад: Оголошення константи починаючи з PHP 7.1.0
<?php
/**
* Визначаємо MyClass
*/
class MyClass
{
// Оголошуємо публічну константу
public const MY_PUBLIC = 'public';
// Оголошуємо protected-константу
protected const MY_PROTECTED = 'protected';
// Оголошуємо private-константу
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; // Fatal Error
MyClass::MY_PRIVATE; // Fatal Error
$myclass->foo(); // Public, Protected і Private працюють
/**
* Визначаємо MyClass2
*/
class MyClass2 extends MyClass
{
// Цей метод публічний
function foo2()
{
echo self::MY_PUBLIC;
echo self::MY_PROTECTED;
echo self::MY_PRIVATE; // Fatal Error
}
}
$myclass2 = new MyClass2;
echo MyClass2::MY_PUBLIC; // Працює
$myclass2->foo2(); // Public і Protected працюють, Private - ні
?>
Видимість з інших обʼєктів
Обʼєкти одного типу мають доступ до private- і protected-членів одне одного, навіть якщо це різні екземпляри. Так відбувається тому, що всередині таких обʼєктів деталі конкретної реалізації вже відомі.
Приклад: Доступ до private-членів обʼєкта того самого типу
<?php
class Test
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
private function bar()
{
echo 'Accessed the private method.';
}
public function baz(Test $other)
{
// Ми можемо змінити private-властивість:
$other->foo = 'hello';
var_dump($other->foo);
// Ми також можемо викликати private-метод:
$other->bar();
}
}
$test = new Test('test');
$test->baz(new Test('other'));
?>
Результат виконання наведеного прикладу:
string(5) "hello"
Accessed the private method.
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.