Отправляет email-рассылки с помощью сервиса Sendsay

PHP 5 для начинающих

  Все выпуски  

Исследование видимости


PHP 5 для начинающих

Свойства и методы класса бывают публичными (public), защищенными (protected) и приватными (private). Приведенная классификация определяет их видимость, или доступность («Видимость»).

При наследовании (inheritance) все свойства и методы родительского класса автоматически принадлежат и классу-наследнику. Тем не менее, приватные свойства и методы родительского класса оказываются при этом недоступны из класса-наследника («Видимость при наследовании»).

Значения свойств родительского класса, установленные по умолчанию, могут быть изменены в классе-наследнике. Сами свойства также могут быть перекрыты (overriding), т. е. объявлены повторно «Перекрытие».

Для изучения видимости (доступа) разработаем несколько тестовых классов, объекты которых и будут подвергнуты исследованию (Пример 16.1, «Тестовые классы для изучения видимости»). Простоты ради при исследовании доступа ограничимся преимущественно свойствами. Также уменьшим количество акцессоров до одного, придав ему максимальную универсальность.

Пример 16.1. Тестовые классы для изучения видимости

<?php

class ParentClass
{
    public $public = 'I am public.'; 1
    protected $protected = 'I am protected.'; 2
    private $private = 'I am private.'; 3

    public function access($propertyName, $newValue = null) 4
    {
        $oldValue = $this->$propertyName; 5
        if (isset($newValue)) { 6
            $this->$propertyName = $newValue; 7
        }
        return $oldValue; 8
    }
}

?>
            
1 2 3

Родительский класс содержит по одному публичному, защищенному и приватному свойству.

4

Единственный акцессор принимает название свойства, к которому осуществляется доступ, и необязательное новое значение этого свойства.

5

Запоминается текущее значение заданного свойства.

6 7

Новое значение будет установлено лишь в том случае, если оно было задано при вызове акцессора.

8

Возвращается старое значение заданного свойства.

<?php

class ChildClass extends ParentClass
{
    function __construct()
    {
        $this->init(); 1
    }

    protected function init()
    {
        $this->public = 'I am public too!'; 2
    }

    public function access2($propertyName, $newValue = null) 3
    {
        $oldValue = $this->$propertyName;
        if (isset($newValue)) {
            $this->$propertyName = $newValue;
        }
        return $oldValue;
    }
}

?>
            
1

Вызов метода init().

2

Устанавливается новое значение публичного свойства.

3

Этот акцессор полностью идентичен определенному в родительском классе, за исключением того, что он определен в классе-наследнике.

<?php

class OverChildClass extends ChildClass
{
    protected function init()
    {
        $this->public = 'I was overridden!'; 1
    }
}

?>
            
1

Устанавливается новое значение публичного свойства.


Для исследования видимости свойств из глобального контекста создадим объект класса ParentClass (см. Пример 16.1, «Тестовые классы для изучения видимости») и попытаемся поочередно напрямую обратиться к его свойствам (Пример 16.2, «Доступ к свойствам объекта из глобального контекста»).

[Замечание]Замечание

Здесь и в ряде последующих примеров приводимый вывод для большей простоты несколько изменен (в частности, в реальном скрипте исполнение было бы прервано после первой же фатальной ошибки).

Пример 16.2. Доступ к свойствам объекта из глобального контекста

<?php

$obj = new ParentClass;

print $obj->public; 1
print $obj->protected; 2
print $obj->private; 3

?>
            
I am public. 1
Fatal error:  Cannot access protected property ParentClass::$protected 2
Fatal error:  Cannot access private property ParentClass::$private 3
            
1 1

Публичное свойство доступно непосредственно из глобального контекста.

2 2

Защищенное свойство из глобального контекста недоступно; попытка обратиться к нему напрямую ведет к возникновению фатальной ошибки.

3 3

Приватное свойство из глобального контекста недоступно; попытка обратиться к нему напрямую ведет к возникновению фатальной ошибки.


Создадим объект класса ChildClass (см. Пример 16.1, «Тестовые классы для изучения видимости») и воспользуемся сначала унаследованным им у класса ParentClass методом access(), а затем собственным акцессором access2().

Пример 16.4. Доступ к унаследованным свойствам

<?php

$obj = new ChildClass;

print $obj->access('public'); 1
print $obj->access('protected');
print $obj->access('private');

?>
            
I am public too! 1
I am protected.
I am private.
            
1 1

Метод access() определен в родительском классе и поэтому имеет доступ ко всем объявленным в нем свойствам (даже будучи вызванным из объекта класса-наследника). В то же время видно, что этот метод обращается к свойствам именно того объекта, из которого он был вызван, о чем свидетельствует вывод измененого в классе-наследника значения публичного свойства.

<?php

print $obj->access2('public');
print $obj->access2('protected');
print $obj->access2('private'); 1

?>
            
I am public too!
I am protected.
Notice:  Undefined property:  ChildClass::$private 1
            
1 1

Метод access2() определен в классе-наследнике; поэтому он «не видит» приватного свойства родительского класса. Тем не менее, это свойство, наряду с остальными, принадлежит объекту класса-наследника. Чтобы убедиться в этом, достаточно его проинспектировать.

print_r($obj);
ChildClass Object
(
    [public] => I am public too!
    [protected:protected] => I am protected.
    [private:private] => I am private.
)
                    

Если видимость перекрытых свойств и методов из самого класса-наследника, в котором и произведено перекытие, представляется достаточно очевидной, то видимость перекрывающих методов класса-наследника из методов, определенных в родительском классе, представляет определенный интерес, так как позволяет придавать приложениям дополнительную гибкость.

Создадим объект класса OverChildClass (Пример 16.5, «Видимость при перекрытии»). Заметим, что в этом классе метод init() нигде явным образом не вызывается.

Пример 16.5. Видимость при перекрытии

<?php

$obj = new OverChildClass;

print $obj->access('public'); 1

?>
            
I was overridden! 1
1 1

Текущее значение публичного свойства было установлено в методе init() класса-наследника OverChildClass, вызванном из конструктора, определенного в родительском классе ChildClass.

[Замечание]Замечание

На самом деле, конечно, само по себе свойство не было перекрыто; оно лишь было изменено в перекрытом методе.


Created with DocBook


В избранное