На текущем практическом занятии будут изучены особенности видимости публичных, защищенных и приватных свойств и методов из глобального контекста, из самого класса, из унаследованного класса, в том числе, при перекрытии.
Свойства и методы класса бывают публичными (public), защищенными (protected) и приватными (private). Приведенная классификация определяет их видимость, или доступность («Видимость»).
При наследовании (inheritance)
все свойства и методы родительского класса автоматически принадлежат и классу-наследнику. Тем не менее, приватные свойства и методы родительского класса оказываются при этом недоступны из класса-наследника («Видимость при наследовании»).
Значения свойств родительского класса, установленные по умолчанию, могут быть изменены в классе-наследнике. Сами свойства также могут
быть перекрыты (overriding), т. е. объявлены повторно «Перекрытие».
Объекты исследования
Для изучения видимости (доступа) разработаем несколько тестовых классов, объекты которых и будут подвергнуты
исследованию (Пример 16.1, «Тестовые классы для изучения видимости»). Простоты ради при исследовании доступа ограничимся преимущественно свойствами. Также уменьшим количество акцессоров до одного, придав ему максимальную универсальность.
Пример 16.1. Тестовые классы для изучения видимости
<?php
class ParentClass
{
public $public = 'I am public.';
protected $protected = 'I am protected.';
private $private = 'I am private.';
public function access($propertyName, $newValue = null)
{
$oldValue = $this->$propertyName;
if (isset($newValue)) {
$this->$propertyName = $newValue;
}
return $oldValue;
}
}
?>
Родительский класс содержит по одному публичному, защищенному и приватному свойству.
Единственный акцессор принимает название свойства, к которому осуществляется доступ, и необязательное новое значение этого свойства.
Запоминается текущее значение заданного свойства.
Новое значение будет установлено лишь в том случае, если оно было задано при вызове акцессора.
Возвращается старое значение заданного свойства.
<?php
class ChildClass extends ParentClass
{
function __construct()
{
$this->init();
}
protected function init()
{
$this->public = 'I am public too!';
}
public function access2($propertyName, $newValue = null)
{
$oldValue = $this->$propertyName;
if (isset($newValue)) {
$this->$propertyName = $newValue;
}
return $oldValue;
}
}
?>
Вызов метода init().
Устанавливается новое значение публичного свойства.
Этот акцессор полностью идентичен определенному в родительском классе, за исключением того, что он определен в классе-наследнике.
<?php
class OverChildClass extends ChildClass
{
protected function init()
{
$this->public = 'I was overridden!';
}
}
?>
Устанавливается новое значение публичного свойства.
Здесь и в ряде последующих примеров приводимый вывод для большей простоты несколько изменен (в частности, в реальном
скрипте исполнение было бы прервано после первой же фатальной ошибки).
Пример 16.2. Доступ к свойствам объекта из глобального контекста
Как видим, класс имеет доступ ко всем без исключения собственным свойствам.
При наследовании
Создадим объект класса ChildClass (см. Пример 16.1, «Тестовые классы для изучения видимости»)
и воспользуемся сначала унаследованным им у класса ParentClass методом access(), а затем собственным акцессором access2().
Метод access() определен в родительском классе и поэтому имеет
доступ ко всем объявленным в нем свойствам (даже будучи вызванным из объекта класса-наследника). В то же время видно, что этот метод обращается к свойствам именно того объекта, из которого он был вызван, о чем свидетельствует вывод измененого в классе-наследника значения публичного свойства.
I am public too!
I am protected.
Notice: Undefined property: ChildClass::$private
Метод access2() определен в классе-наследнике; поэтому он
«не видит» приватного свойства родительского класса. Тем не менее, это свойство, наряду с остальными, принадлежит объекту класса-наследника. Чтобы убедиться в этом, достаточно его проинспектировать.
print_r($obj);
ChildClass Object
(
[public] => I am public too!
[protected:protected] => I am protected.
[private:private] => I am private.
)
При перекрытии
Если видимость перекрытых свойств и методов из самого класса-наследника, в котором и произведено перекытие, представляется достаточно очевидной, то видимость перекрывающих методов класса-наследника из методов, определенных в родительском классе, представляет определенный интерес,
так как позволяет придавать приложениям дополнительную гибкость.
<?php
$obj = new OverChildClass;
print $obj->access('public');
?>
I was overridden!
Текущее значение публичного свойства было установлено в методе init() класса-наследника OverChildClass, вызванном из конструктора, определенного в родительском классе ChildClass.
Замечание
На самом деле, конечно, само по себе свойство не было перекрыто; оно лишь было изменено в перекрытом методе.