Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Перехват обращений к членам класса

Лабораторная работа №6. Модификаторы доступа

До сих пор мы объявляли свойства и методы класса, не задумываясь особенно, должны ли они быть доступны в программе, или же используются только для внутренних целей. Модификатор public, знакомый нам по предыдущей главе, имеет как раз такой смысл. Однако в крупных программах, а также законченных библиотеках следует ограничивать доступ к свойствам и методам классов, разрешая только то, что действительно необходимо программе, и "скрывая" все остальное.

ЗАМЕЧАНИЕ

Чаще всего стараются не делать открытыми свойства класса. предоставляя доступ к ним только через специальные методы. Так можно. например, запретить в программе изменение того или иного свойства.

Модификаторы доступа

В РНР существуют три модификатора ограничения доступа: public, protected и private. Их можно указывать перед описанием метода или свойства класса.

Рubliс: открытый доступ

Члены класса, помеченные ключевым словом public ("публичный", "открытый"), доступны для использования извне класса (например, из вызывающей программы). Вот пример:

Private: доступ только из методов класса

С использованием ключевого слова private ("личный", "закрытый") вы можете сделать члены касса "невидимыми" из вызывающей программы, будто бы их и нет. В то же время, методы "своего" класса могут обращаться к ним без всякого ограничения. Пример:

Как видите, модификатор private включает максимально возможные ограничения на доступ к членам класса. Он разрабатывался специально для того, чтобы запретить прямое изменение свойств объекта, а также доступ к различным служебным методам.

Protected: доступ из методов производного класса

Модификатор protected ("защищенный") с точки зрения вызывающей программы выглядит точно так же, как и private: он запрещает доступ к членам объекта извне. Однако по сравнению с private он более "либерален", ибо позволяет обращаться к членам не только из "своих" методов, но также и из методов производных классов (если используется наследование). О наследовании мы подробно поговорим в следующей главе, а пока только скажем, что "защищенными" обычно делают лишь методы, но не свойства классов. Это позволяет создавать "полуслужебные" функции, которые, с одной стороны, выполняют низкоуровневые действия и не должны быть "видны" в основной программе, а с другой, могут использоваться в классах-потомках.

Неявное объявление свойств

Давайте остановимся на одной интересной особенности РНР. Речь идет о том, что операторы:

$this->property = 101;

$obj->property = 303;

допустимы и не вызывают ошибку даже в случае, если свойство $property в классе не объявлено. В этом отношении объекты очень похожи на ассоциативные массивы: в них можно создавать произвольные ключи, а также возможно ограничить доступ к некоторым из них (например, с помощью модификатора private). Применим даже такой синтаксис:

$key = "test";

$obj->$key = 314;

При этом в объекте $obj создастся свойство с именем Stest и значением 314, а РНР даже "не пикнет", в том числе в режиме контроля ошибок E_ALL|E_STRICT.

Общие рекомендации

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

Вот некоторые из них:

· Скрывайте при помощи модификатора private как можно больше данных и методов. Оставляйте открытыми только те члены класса, которые действительно моrут при­годиться вызывающей программе.

· Не создавайте открытых методов "про запас". Если в будущем какой-то из них понадобится в вызывающей программе, всегда можно изменить его модификатор доступа. Помните: "открыть" метод всегда проще, чем "закрыть" его впоследствии (ибо, сменив модификатор метода с public на private, нам придется проверить все скрипты, которые используют наш класс).

· Группируйте открытые методы в начале класса, а закрытые - в его конце. Это поможет выделить интерфейс класса (методы, доступные извне).

· Старайтесь не создавать открытые свойства вообще. Делайте их закрытыми (private) или, в крайнем случае, - защищенными (protected). Доступ к свойствам лучше организовывать при помощи открытых методов - так можно, например, запретить изменение свойства, или выполнить некоторые действия перед его считыванием.

Класс - self, объект - $this

Классы выступают в качестве шаблонов для объектов. Для того чтобы обратиться к внутреннему содержимому объекта, используется ключевое слово Sthis. Для обращения к внутреннему содержимому класса используется ключевое слово self (рис. 1). Как видно, ключевое слово $this снабжено символом доллара, чтобы подчеркнуть связь с переменными. В то время как ключевое слово self обходится без символа доллара - это указание на то, что обращаемся мы не к переменной.

Рис. 1. self используется дм обращения к внутренним переменным и методам класса, а $this - к переменным и методам объекта

Особенностью статических членов и методов является тот факт, что они определяются не на уровне объекта, а на уровне класса.

Статическое свойство недоступно через обращение $this->property или $obj->property. Вместо этого используется оператор:: и либо имя класса (ИмяКласса:: $property), либо ключевое слово self {self:: $property).

Статический метод во время своего запуска не получает ссылку $this, поэтому он может работать только со статическими членами (свойствами и другими методами) своего класса.

Пример: счетчик объектов

Давайте рассмотрим пример класса, который "считает", сколько его экземпляров (объектов) существует в текущий момент, и позволяет получить эту информацию из вызывающей программы (листинг 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

АМЕЧАННИЕ

При проверке классовых констант следует в обязательном порядке использовать оператор разрешения области видимости:: и имя класса.

Перехват обращений к членам класса

РНР позволяет "перехватывать" обращения к несуществующим членам объекта. Для этого в класс необходимо добавить специальные методы, имена которых начинаются с двойного подчерка. Перехватывать можно запросы трех видов.

1. Получение величины свойства объекта. Каждый раз, когда в программе производится попытка обратиться к некоторому несуществующему свойству на чтение, РНР пытается запустить метод __get() класса, передав ему в параметрах имя свойства. Если же свойство уже есть в объекте (например, объявлено в классе или же присвоено каким-либо другим образом), то никакого перехвата не происходит - РНР сразу же обращается к соответствующей переменной.

2. Установка нового значения для свойства. В случае если мы присваиваем некоторую величину несуществующему свойству класса. РНР пытается выполнить метод __set(). передав в параметрах имя свойства и его новое значение. Опять же, если свойство с указанным именем уже существует, вызова метода не происходит.

3. Запуск несуществующего метода класса. Если для некоторого объекта вызывается метод с незарегистрированным в классе именем, РНР запускает специальную функцию __call(), передавая ей два параметра: имя несуществующего метода и список аргументов, использованных при вызове. Метод __call() может отработать и вернуть некоторое значение, которое в итоге получит вызывающая программа.

Все три типа перехвата происходят для вызывающей программы совершенно "прозрачно": она может даже "не заметить", что произошел вызов служебного метода. Листинг 4 иллюстрирует сказанное на примере. В нем определяется класс Hooker, который перехватывает запросы ко всем несуществующим членам объекта (свойствам и методам). Во время присваивания значения свойству он дополнительно выполняет операцию trim() для значения. Таким образом, все величины, хранящиеся в данном классе, не будут содержать ведущих и концевых пробелов.

Листинг 4 Перехват обращений к членам класса. Файл overload.php

Обратите внимание на то, что обращения к "обычному" свойству $opened, а также к методу method() не было перехвачено.

ПРИМЕЧАНИЕ

Вы можете считать, что в любом классе всегда определены перехватчики _get(), _set() и _call(), однако по умолчанию они генерируют сообщение об ошибке: попытка обращения к несуществующему члену класса. Когда вы вводите свои перехватчики, то изменяете такое поведение.

Клонирование объектов

Как уже неоднократно говорилось выше, в РНР объекты представляют собой ссылку. Во время присваивания ссылочных переменных объекты, на которые они ссылаются, уже не копируются - дублируются лишь сами ссылки.

Но что же делать, если нам в действительности нужно получить дубликат некоторого объекта, а не лишь еще одну ссылку на него? Для данных целей применяется ключевое слово clone (листинг 5).

Листинг 5 Встроенное клонирование объектов. Файл clone0.php

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...