Перехват обращений к членам класса
Лабораторная работа №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 Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|