Текст/Составлено Чжу Сяньчжуном
1. Введение
К счастью, технология перегрузки объектов была представлена в PHP 5.0. В этой статье будет рассмотрена возможность перегрузки методов __call(), __set() и __get(). После краткого введения в теорию перегрузки мы перейдем непосредственно к теме и рассмотрим два примера: первый пример — реализация класса постоянного хранилища, второй — поиск способа реализации динамического метода получения/установки;
2. Что такое перегрузка объекта?
Говоря о перегрузке объектов в PHP, мы должны различать два типа:
· Перегрузка метода
· Перегрузка атрибута.
В случае перегрузки метода мы должны определить магический метод __call(), который будет реализовывать общий вызов неопределенного метода. в соответствующем классе. Этот общий метод вызывается только тогда, когда вы хотите получить доступ к неопределенному методу в классе. Без перегрузки метода следующий пример приведет к тому, что PHP отобразит сообщение о фатальной ошибке: Вызовите неопределенный метод ThisWillFail::bar() в /some/directory/example.php в строке 9 и прервите выполнение программы:
< ?php
класс ThisWillFail {
публичная функция foo() {
вернуть «Привет, мир!»;
}
}
$класс = новый ThisWillFail;
$класс->бар();
?>
С помощью перегрузки методов код может перехватить этот вызов и корректно его обработать.
Перегрузка свойств аналогична перегрузке методов. В этом случае класс перенаправляет (также называемое проксированием) операции чтения/записи на свойства класса, которые не определены явно в классе. Специализированные методы здесь — __set() и __get(). В зависимости от уровня сообщения об ошибках переводчик PHP обычно либо выдает уведомление при доступе к неопределенному свойству, либо откладывает и потенциально определяет переменную. Если вы используете перегрузку атрибутов, переводчик может вызвать __set() при установке неопределенного атрибута и вызвать __get() при доступе к неопределенному значению атрибута.
Подводя итог, можно сказать, что использование технологии перегрузки может значительно сократить время разработки программного обеспечения при использовании динамических языков, таких как PHP.
На этом этапе вводится теория, а конкретное кодирование анализируется ниже.
3. Примеры классов постоянного хранилища
Следующий код реализует упомянутый выше класс постоянного хранилища менее чем 50 строками кода PHP с использованием технологии перегрузки атрибутов. Термин «постоянный» означает, что класс может описывать элемент структуры данных и оставаться синхронизированным с базовой системой хранения. С точки зрения кодирования, внешний код может использовать классы для выбора строки из таблицы базы данных. Таким образом, когда программа запущена, вы можете напрямую обращаться к атрибутам класса для управления элементами в строке (чтение/выборка). В конце сценария PHP будет отвечать за отправку обновленных данных строки обратно в базу данных.
Внимательное изучение следующего кода поможет вам понять, что такое перегрузка атрибутов.
<?php
//Загрузка пакета базы данных PEAR <a href=" http://pear.php.net/package/DB/ "> DB</a>
require_once "DB.php";
класс Постоянный {
частные $данные = массив();
частная $table = "пользователи";
общественная функция __construct($user) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");
$query = "ВЫБЕРИТЕ идентификатор, имя, адрес электронной почты, страну ОТ" .
$this->таблица "ГДЕ имя =?";
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}
публичная функция __get($member) {
if (isset($this->data[$member])) {
вернуть $this->data[$member];
}
}
публичная функция __set($member, $value) {
//Идентификатор набора данных доступен только для чтения, если ($member == "id") {
возвращаться;
}
if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}
публичная функция __destruct() {
$query = "ОБНОВЛЕНИЕ" $this->table " SET name = ?,
электронная почта = ?, страна = ? ГДЕ идентификатор =?";
$this->dbh->query($query, $this->name, $this->email,
$this->country, $this->id);
}
}
$class = new Persistable("Мартин Янсен");
$class->name = "Джон Доу";
$class->country = "США";
$class->email = " [email protected] ";
?>
Первая проблема, с которой вы можете столкнуться, — это __construct(), новый метод конструктора, представленный в PHP 5. Во времена PHP 4 конструкторы всегда соответствовали именам классов. В PHP 5 это уже не так. Вам не нужно много знать о методе-конструкторе, за исключением того, что его вызов создает экземпляр класса и обратите внимание, что здесь используется параметр — база данных выполняется на основе этого параметра; Этот конструктор присваивает результаты запроса атрибуту класса $data.
Далее программа определяет два специальных метода __get() и __set(). Вы уже должны быть с ними знакомы: __get() используется для чтения неопределенных значений атрибутов, а __set() используется для изменения неопределенных значений атрибутов.
Это означает, что всякий раз, когда неопределенное свойство считывается/записывается из класса постоянного хранилища, эти специализированные методы отвечают за управление информацией в переменной $data массива свойств, а не за непосредственное изменение свойств класса (помните: переменная $data содержит строку из базы данных!).
Последний метод в классе является противоположностью __construct() — деструктором __destruct(). PHP вызывает деструктор во время «фазы завершения работы скрипта», которая обычно находится ближе к концу выполнения PHP-скрипта. Деструктор записывает информацию из атрибута $data обратно в базу данных. Именно это и означает предыдущий термин «синхронизация».
Возможно, вы заметили, что в приведенном здесь коде используется пакет уровня абстракции базы данных PEAR. На самом деле это не имеет значения. Связь с базой данных другими методами также может проиллюстрировать тему этой статьи.
Если вы посмотрите внимательно, вы обнаружите, что описание этого класса постоянного хранилища относительно просто. В примере используется только таблица базы данных и не рассматриваются более сложные модели данных, такие как использование LEFT JOIN и другие сложные методы работы с базой данных. Однако вам не обязательно быть связанными этим, и с помощью перегрузки свойств вы можете использовать свою собственную идеальную модель базы данных. Написав всего лишь немного кода, вы сможете воспользоваться преимуществами сложных функций базы данных в этом классе постоянного хранилища.
Есть еще небольшая проблема — не вводится механизм обработки ошибок при сбое запроса в деструкторе. Такова природа деструкторов, которая делает невозможным отображение соответствующего сообщения об ошибке в этом случае, поскольку построение HTML-разметки часто заканчивается до того, как PHP вызовет деструктор.
Чтобы решить эту проблему, вы можете переименовать __destruct() во что-то вроде saveData() и выполнить этот метод вручную где-нибудь в вызывающем скрипте. Это не меняет концепцию постоянного хранилища классов; это всего лишь несколько строк кода. Альтернативно вы можете использовать функцию error_log() в деструкторе для регистрации сообщения об ошибке в общесистемном файле журнала ошибок.
Вот как работает перегрузка свойств. Далее мы обсудим перегрузку методов.
4. Примеры перегрузки методов
1. Динамические методы получения/установки
Следующий код реализует «динамические» методы получения/установки для управления классом с помощью перегрузки методов. Давайте проанализируем его на основе исходного кода:
<?php
класс DynamicGetterSetter {
Private $name = "Мартин Янсен";
Private $starbucksdrink = "Вихрь карамельного капучино";
функция __call($метод, $аргументы) {
$prefix = strtolower(substr($method, 0, 3));
$property = strtolower(substr($method, 3));
if (пустой($префикс) || пустой($свойство)) {
возвращаться;
}
if ($prefix == "get" && isset($this->$property)) {
вернуть $this->$property;
}
if ($prefix == "установить") {
$this->$property = $arguments[0];
}
}
}
$класс = новый DynamicGetterSetter;
echo "Имя:" $class->getName() "n";
echo "Любимый вкус Starbucks: " $class->getStarbucksDrink() "nn";
$class->setName("Джон Доу");
$class->setStarbucksDrink("Классический кофе");
echo "Имя:" $class->getName() "n";
echo "Любимый вкус Starbucks: " $class->getStarbucksDrink() "nn";
?>
Очевидно, что два атрибута $name и $starbucksdrink здесь являются частными, а это означает, что к этим атрибутам нельзя получить доступ извне класса. В объектно-ориентированном программировании очень часто реализуются общедоступные методы получения/установки для доступа или изменения значений закрытых свойств. Их реализация утомительна и отнимает много времени и усилий.
Эту проблему можно легко решить с помощью перегрузки методов. Вместо реализации методов получения/установки для каждого свойства приведенный выше пример реализует только общий метод __call(). Это означает, что при вызове неопределенного метода получения/установки, такого как setName() или getStarbucksdrink(), PHP не будет генерировать фатальную ошибку и прерывать работу, а вместо этого выполнит (или делегирует) магический метод __call().
Это краткое введение. Давайте проведем углубленный анализ __call().
2. Подробный анализ метода __call().
Первый параметр __call() — это исходный и неопределенный метод (например, setName). Второй параметр — это одномерный массив с числовым индексом, который содержит все оригинальные методы. параметр. Вызов неопределенного метода с двумя параметрами ("Мартин" и 42) создаст следующий массив:
$class->thisMethodDoesNotExist("Мартин", 42);
/Руководство по второму параметру __call()
Множество
(
[0] =>Мартин
[1] => 42
)
Внутри метода __call(), если исходный метод начинается с get или set, необходимо выполнить некоторые вычисления, чтобы определить, вызывает ли код метод получения/установки. Более того, этот метод дополнительно проанализирует еще один компонент имени метода (за исключением первых трех символов), поскольку последняя часть строки представляет собой имя атрибута, на который ссылается метод получения/установки.
Если имя метода указывает на метод получения/установки, то метод либо возвращает соответствующее значение свойства, либо устанавливает значение первого параметра исходного метода. В противном случае он ничего не делает и продолжает выполнение программы, как будто ничего не произошло.
3. Для достижения цели
По сути, для любого атрибута существует метод, который позволяет коду динамически вызывать любой метод получения/установки. Этот алгоритм существует. Это удобно при разработке прототипа программы в краткосрочной перспективе: вместо того, чтобы тратить много времени на реализацию геттеров/сеттеров, разработчик может сосредоточиться на моделировании API и обеспечении фундаментальной корректности приложения. Включение метода __call() в абстрактный класс может даже позволить вам повторно использовать код в будущей разработке PHP-проекта.
4. Помимо недостатков,
у него есть свои преимущества и недостатки! У описанного выше подхода есть несколько недостатков: В крупных проектах могут использоваться такие инструменты, как phpDocumentor, для отслеживания структуры API. Конечно, при использовании динамического метода, представленного выше, все методы получения/установки не будут отображаться в автоматически созданном документе, что не требует дальнейшего объяснения.
Еще одним недостатком является то, что код вне класса может получить доступ к каждому частному свойству внутри класса. При использовании реальных методов получения/установки можно различать частные свойства, к которым может получить доступ внешний код, и «реальные» частные свойства, которые не видны за пределами класса, поскольку у нас есть перегрузка методов, а также виртуальные геттеры и сеттеры. Можно использовать методы.
5. Заключение
В этой статье на двух примерах тщательно анализируются две ситуации перегрузки объектов в PHP 5.0. Я очень надеюсь, что метод, описанный в этой статье, поможет вам повысить эффективность программирования на PHP. В то же время вы также должны ясно увидеть недостатки этого метода!