- •Лабораторная работа №6. Модификаторы доступа
- •Модификаторы доступа
- •Рubliс: открытый доступ
- •Private: доступ только из методов класса
- •Protected: доступ из методов производного класса
- •Неявное объявление свойств
- •Общие рекомендации
- •Константы класса
- •3Амечанние
- •Перехват обращений к членам класса
- •Пример: счетчик объектов
- •Пример: кэш ресурсов
- •Клонирование объектов
- •Переопределение операции клонирования
- •Запрет клонирования
- •Перехват сериализации
- •Методы _sleep() и _wakeup()
- •Задания для самостоятельного решения
Пример: счетчик объектов
Давайте рассмотрим пример класса, который "считает", сколько его экземпляров (объектов) существует в текущий момент, и позволяет получить эту информацию из вызывающей программы (листинг 1).
Листинг 1 Использование статических членов класса. Файл static.php
ВНИМАНИЕ!
Взгляните еще раз на конструктор класса: в нем мы используем команду self::$count++, а не $this->count++. Как уже говорилось выше, статическое свойство принадлежат не объекту, а самому классу, поэтому в $this, представляющем данные объекта, его попросту нет. Тем не менее обращение $this->count++ не порождает ошибку во время выполнения программы! Будьте внимательны.
Пример: кэш ресурсов
Выше мы рассматривали класс FileLogger, который позволяет добавлять сообщения в lоg-файлы. Однако, наверное, не очень хорошо создавать несколько объектов для одного и того же физического файла. Хотелось бы сделать так, чтобы при указании одинаковых имен файлов система не создавала новые объекты, а просто возвращала уже существующие. Такой подход называется кэшированием ресурса по идентификатору (в качестве ресурса тут выступает файл, а в качестве его идентификатора - имя файла). Пример - в листинге 2.
Листинг 2 Локальное кеширование ресурса. Файл cache.php
Заметив, что времена создания переменных совпадают, мы и убеждаемся, что в действительности $logger1 и $ logger2 - ссылки на один и тот же объект.
Обратите внимание, что для запрета прямого создания объектов FileLogger мы использовали закрытый конструктор. Это гарантирует, что массив FileLogger::$loggers будет всегда содержать актуальные значения, которые "не испортятся" в результате действий сторонней программы.
Константы класса
Наряду с членами классы могут содержать константы, которые определяются при помощи ключевого слова const. В листинге 3 приводится пример класса cls, включающего в свой состав константу NАМЕ, которая содержит имя класса.
Листинг 3. Использование констант к классах. Файл const.php
Точно так же, как и в случае со статическими членами классов, к константам нельзя обращаться при помощи оператора->; для обращения используется оператор разрешения области видимости :: который предваряется либо именем класса. либо ключевым словом self.
Существование констант может быть проверено при помощи функции defined(), которая возвращает true, если константа существует, и false в противном случае (листинг 4).
Листинг 3 Проверка существования констант класса. Файл defined.php
3Амечанние
При проверке классовых констант следует в обязательном порядке использовать оператор разрешения области видимости :: и имя класса.
Перехват обращений к членам класса
РНР позволяет "перехватывать" обращения к несуществующим членам объекта. Для этого в класс необходимо добавить специальные методы, имена которых начинаются с двойного подчерка. Перехватывать можно запросы трех видов.
Получение величины свойства объекта. Каждый раз, когда в программе производится попытка обратиться к некоторому несуществующему свойству на чтение, РНР пытается запустить метод __get() класса, передав ему в параметрах имя свойства. Если же свойство уже есть в объекте (например, объявлено в классе или же присвоено каким-либо другим образом), то никакого перехвата не происходит - РНР сразу же обращается к соответствующей переменной.
Установка нового значения для свойства. В случае если мы присваиваем некоторую величину несуществующему свойству класса. РНР пытается выполнить метод __set(). передав в параметрах имя свойства и его новое значение. Опять же, если свойство с указанным именем уже существует, вызова метода не происходит.
Запуск несуществующего метода класса. Если для некоторого объекта вызывается метод с незарегистрированным в классе именем, РНР запускает специальную функцию __call() , передавая ей два параметра: имя несуществующего метода и список аргументов, использованных при вызове. Метод __call() может отработать и вернуть некоторое значение, которое в итоге получит вызывающая программа.
Все три типа перехвата происходят для вызывающей программы совершенно "прозрачно": она может даже "не заметить", что произошел вызов служебного метода. Листинг 4 иллюстрирует сказанное на примере. В нем определяется класс Hooker, который перехватывает запросы ко всем несуществующим членам объекта (свойствам и методам). Во время присваивания значения свойству он дополнительно выполняет операцию trim() для значения. Таким образом, все величины, хранящиеся в данном классе, не будут содержать ведущих и концевых пробелов.
Листинг 4 Перехват обращений к членам класса. Файл overload.php
Обратите внимание на то, что обращения к "обычному" свойству $opened, а также к методу method() не было перехвачено.
ПРИМЕЧАНИЕ
Вы можете считать, что в любом классе всегда определены перехватчики _get(), _set() и _call() , однако по умолчанию они генерируют сообщение об ошибке: попытка обращения к несуществующему члену класса. Когда вы вводите свои перехватчики, то изменяете такое поведение.
