Області видимості властивостей, методів або (починаючи з PHP 7.1.0) констант
можуть визначатись через ключові слова public
(загальнодоступно), protected
(захищено) чи
private
(закрито). Доступ до членів класу, оголошених як
загальнодоступні, дозволено всюди. Члени класу, оголошені як захищені,
доступні лише всередині самого класу, а також через класи-нащадки та
батьківські класи. Члени класу, оголошені як закриті можуть бути доступні
лише в класі, де вони визначені.
Властивості класу можуть оголошуватись як загальнодоступні, захищені чи закриті. Властивість, оголошена без ключового слова видимості, вважається загальнодоступною.
Приклад #1 Оголошення властивості
<?php
/**
* Визначення MyClass
*/
class MyClass
{
public $public = 'Загальнодоступна';
protected $protected = 'Захищена';
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(); // Виводить Загальнодоступна, Захищена та Закрита
/**
* Визначення MyClass2
*/
class MyClass2 extends MyClass
{
// Ми можемо перевизначити public- та protected-властивості, але не private
public $public = 'Public2';
protected $protected = 'Захищена2';
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(); // Виводить Загальнодоступна2, Захищена2, Закрита
?>
Починаючи з PHP 8.4, властивості можуть мати асиметричну видимість, з
різними областями видимості для читання (get
) та запису
(set
). Зокрема видимість 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; // Fatal Error
}
}
$b = new Book('Програмування на PHP', 'Петро Петрук', 2024);
echo $b->title; // Працює
echo $b->author; // Працює
echo $b->pubYear; // Fatal Error
$b->title = 'Як не програмувати на PHP'; // Fatal Error
$b->author = 'Павло Петрук'; // Fatal Error
$b->pubYear = 2023; // Fatal Error
?>
Є кілька застережень щодо асиметричної видимості:
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
, як більш
обмежувальна.
Клас-нащадок може перевизначати властивість батьківського класу, якщо та не
фінальна (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, private чи protected. Метод, оголошений без ключового слова видимості, вважається загальнодоступним.
Приклад #4 Оголошення метода
<?php
/**
* Визначення MyClass
*/
class MyClass
{
// Оголошення загальнодоступного конструктора
public function __construct() { }
// Оголошення загальнодоступного методу
public function MyPublic() { }
// Оголошення захищеного методу
protected function MyProtected() { }
// Оголошення закритого методу
private function MyPrivate() { }
// Таке оголошення метода буде оброблятись як public метод
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // Працює
$myclass->MyProtected(); // Фатальна помилка
$myclass->MyPrivate(); // Фатальна помилка
$myclass->Foo(); // Працюють Public, Protected та Private методи
/**
* Визначення MyClass2
*/
class MyClass2 extends MyClass
{
// Таке оголошення методу буде оброблятись як public
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Фатальна помилка
}
}
$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. Константа, оголошена без ключового слова видимості, вважається загальнодоступною.
Приклад #5 Оголошення констант, починаючи з PHP 7.1.0
<?php
/**
* Define 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
?>
Однотипні об'єкти мають доступ до методів та властивостей один одного, що оголошені як private або protected, навіть якщо ці об'єкти не є одним і тим же примірником. Це пояснюється тим, що впровадження механізму видимості відбувається відносно класів цих об'єктів, а не відносно самих об'єктів.
Приклад #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(12) "привіт" Доступ до закритого методу.