Область видимости
Область видимости свойства или метода может быть определена путем использования следующих ключевых слов в объявлении: public, protected или private. Доступ к свойствам и методам классам, объявленным как public (общедоступный), может происходить из любого места. Модификатор protected (защищенный) позволяет иметь доступ наследуемым и родительским классам (а, также классу, в котором определен сам член класса). Модификатор private (закрытый) ограничивает область видимости так, что только класс, где объявлен сам элемент, имеет к нему доступ.
Область видимости свойств
Свойства класса должны быть определены через модификаторы public, private, или protected.
Пример #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
protected $protected = 'Защищенный2';
function printHello()
{
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj2 = new MyClass2();
echo $obj2->public; // Работает
echo $obj2->private; // Неопределен
echo $obj2->protected; // Неисправимая ошибка
$obj2->printHello(); // Выводит Общий, Защищенный2 и Закрытый
?>
Замечание: Метод объявления переменной через ключевое слово var, принятый в PHP 4, до сих пор поддерживается в целях совместимости (как синоним ключевого слова public). В версиях PHP 5 ниже 5.1.3 такое использование выводит предупреждение E_STRICT.
Область видимости метода
Методы класса должны быть определены через модификаторы public, private, или protected. Методы, где определение модификатора отсутствует, определяются как public.
Пример #2 Объявление метода
<?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
?>
- Введение
- Основы
- Свойства
- Константы классов
- Автоматическая загрузка классов
- Конструкторы и деструкторы
- Область видимости
- Наследование
- Оператор разрешения области видимости (::)
- Ключевое слово "static"
- Абстрактные классы
- Интерфейсы объектов
- Трейты
- Anonymous classes
- Перегрузка
- Итераторы объектов
- Магические методы
- Ключевое слово "final"
- Клонирование объектов
- Сравнение объектов
- Контроль типа
- Позднее статическое связывание
- Объекты и ссылки
- Сериализация объектов
- Журнал изменений ООП
Коментарии
I couldn't find this documented anywhere, but you can access protected and private member varaibles in different instance of the same class, just as you would expect
i.e.
<?php
class A
{
protected $prot;
private $priv;
public function __construct($a, $b)
{
$this->prot = $a;
$this->priv = $b;
}
public function print_other(A $other)
{
echo $other->prot;
echo $other->priv;
}
}
class B extends A
{
}
$a = new A("a_protected", "a_private");
$other_a = new A("other_a_protected", "other_a_private");
$b = new B("b_protected", "ba_private");
$other_a->print_other($a); //echoes a_protected and a_private
$other_a->print_other($b); //echoes b_protected and ba_private
$b->print_other($a); //echoes a_protected and a_private
?>
if not overwritten, self::$foo in a subclass actually refers to parent's self::$foo
<?php
class one
{
protected static $foo = "bar";
public function change_foo($value)
{
self::$foo = $value;
}
}
class two extends one
{
public function tell_me()
{
echo self::$foo;
}
}
$first = new one;
$second = new two;
$second->tell_me(); // bar
$first->change_foo("restaurant");
$second->tell_me(); // restaurant
?>
Just a quick note that it's possible to declare visibility for multiple properties at the same time, by separating them by commas.
eg:
<?php
class a
{
protected $a, $b;
public $c, $d;
private $e, $f;
}
?>
> Members declared protected can be accessed only within
> the class itself and by inherited classes. Members declared
> as private may only be accessed by the class that defines
> the member.
This is not strictly true. Code outside the object can get and set private and protected members:
<?php
class Sealed { private $value = 'foo'; }
$sealed = new Sealed;
var_dump($sealed); // private $value => string(3) "foo"
call_user_func(\Closure::bind(
function () use ($sealed) { $sealed->value = 'BAZ'; },
null,
$sealed
));
var_dump($sealed); // private $value => string(3) "BAZ"
?>
The magic lay in \Closure::bind, which allows an anonymous function to bind to a particular class scope. The documentation on \Closure::bind says:
> If an object is given, the type of the object will be used
> instead. This determines the visibility of protected and
> private methods of the bound object.
So, effectively, we're adding a run-time setter to $sealed, then calling that setter. This can be elaborated to generic functions that can force set and force get object members:
<?php
function force_set($object, $property, $value) {
call_user_func(\Closure::bind(
function () use ($object, $property, $value) {
$object->{$property} = $value;
},
null,
$object
));
}
function force_get($object, $property) {
return call_user_func(\Closure::bind(
function () use ($object, $property) {
return $object->{$property};
},
null,
$object
));
}
force_set($sealed, 'value', 'quux');
var_dump(force_get($sealed, 'value')); // 'quux'
?>
You should probably not rely on this ability for production quality code, but having this ability for debugging and testing is handy.
I see we can redeclare private properties into child class
<?php
class A{
private int $private_prop = 4;
protected int $protected_prop = 8;
}
class B extends A{
private int $private_prop = 7; // we can redeclare private property!!!
public function printAll() {
echo $this->private_prop;
echo $this->protected_prop;
}
}
$b = new B;
$b->printAll(); // show 78
}
?>
Dynamic properties are "public".
<?php
class MyClass {
public function setProperty($value) {
$this->dynamicProperty = $value;
}
}
$obj = new MyClass();
$obj->setProperty('Hello World');
echo $obj->dynamicProperty; // Outputs "Hello World"
?>
This usage is the same as well:
<?php
class MyClass {
}
$obj = new MyClass();
$obj->dynamicProperty = 'Hello World';
echo $obj->dynamicProperty; // Outputs "Hello World"
?>