Перегрузка в PHP означает возможность динамически "создавать" свойства и методы. Эти динамические сущности обрабатываются с помощью "волшебных" методов, которые можно создать в классе для различных видов действий.
Методы перегрузки вызываются при взаимодействии с теми свойствами или методами, которые не были объявлены или не видны в текущей области видимости. Далее в этом разделе мы будем использовать термины "недоступные свойства" или "недоступные методы" для отражения этой комбинации объявления и области видимости.
Все методы перегрузки должны быть объявлены как public.
Замечание:
Ни один аргумент не может быть передан по ссылке в эти "волшебные" методы.
Замечание:
Интерпретация "перегрузки" в PHP отличается от остальных объектно-ориентированных языков. Традиционно перегрузка означает возможность иметь множество одноименных методов с разным количеством или различными типами аргументов.
Версия | Описание |
---|---|
5.3.0 | Добавлен метод __callStatic(). Добавлено предупреждение об усилении публичной видимости и не-статичном объявлении. |
5.1.0 | Добавлены методы __isset() и __unset(). |
Метод __set() будет выполнен при записи данных в недоступные свойства.
Метод __get() будет выполнен при чтении данных из недоступных свойств.
Метод __isset() будет выполнен при использовании isset() или empty() на недоступных свойствах.
Метод __unset() будет выполнен при вызове unset() на недоступном свойстве.
Аргумент $name представляет собой имя вызываемого свойства. Метод __set() содержит аргумент $value, представляющий собой значение, которое будет записано в свойство с именем $name.
Перегрузка свойств работает только в контексте объекта. Данные магические методы не будут вызваны в статическом контексте. Поэтому данные методы не должны объявляться статичными. Начиная с версии PHP 5.3.0, при объявлении "волшебного" метода в качестве static будет показано предупреждение.
Замечание:
Возвращаемое значение метода __set() будет проигнорировано из-за способа обработки в PHP оператора присваивания. Аналогично, __get() никогда не вызовется при цепных присваиваниях, например, таких:
$a = $obj->b = 8;
Замечание:
Невозможно использовать перегруженные свойства в других языковых конструкциях, кроме isset(). Это означает, что если на перегруженном свойстве будет вызвана конструкция empty(), то перегруженный метод не будет вызван.
Для обхода этого ограничения можно скопировать перегруженное свойство в локальную переменную и затем применить к ней empty().
Пример #1 Перегрузка свойств с помощью методов __get(), __set(), __isset() и __unset()
<?php
class PropertyTest {
/** Место хранения перегружаемых данных. */
private $data = array();
/** Перегрузка не применяется к объявленным свойствам. */
public $declared = 1;
/** Здесь перегрузка будет использована только при доступе вне класса. */
private $hidden = 2;
public function __set($name, $value) {
echo "Установка '$name' в '$value'\n";
$this->data[$name] = $value;
}
public function __get($name) {
echo "Получение '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Неопределенное свойство в __get(): ' . $name .
' в файле ' . $trace[0]['file'] .
' на строке ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
/** Начиная с версии PHP 5.1.0 */
public function __isset($name) {
echo "Установлено ли '$name'?\n";
return isset($this->data[$name]);
}
/** Начиная с версии PHP 5.1.0 */
public function __unset($name) {
echo "Уничтожение '$name'\n";
unset($this->data[$name]);
}
/** Не "волшебный" метод, просто для примера. */
public function getHidden() {
return $this->hidden;
}
}
echo "<pre>\n";
$obj = new PropertyTest;
$obj->a = 1;
echo $obj->a . "\n\n";
var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";
echo $obj->declared . "\n\n";
echo "Давайте поэкспериментируем с private свойством 'hidden':\n";
echo "Private свойства видны внутри класса, поэтому __get() не используется...\n";
echo $obj->getHidden() . "\n";
echo "Private свойства не видны вне класса, поэтому __get() используется...\n";
echo $obj->hidden . "\n";
?>
Результат выполнения данного примера:
Установка 'a' в '1' Получение 'a' 1 Установлено ли 'a'? bool(true) Уничтожение 'a' Установлено ли 'a'? bool(false) 1 Давайте поэкспериментируем с private свойством 'hidden': Private свойства видны внутри класса, поэтому __get() не используется... 2 Private свойства не видны вне класса, поэтому __get() используется... Получение 'hidden' Notice: Неопределенное свойство в __get(): hidden в файле <file> на строке 70 в <file> на строке 29
В контексте объекта при вызове недоступных методов вызывается метод __call().
В статическом контексте при вызове недоступных методов вызывается метод __callStatic().
Аргумент $name представляет собой имя вызываемого метода. Аргумент $arguments представляет собой числовой массив, содержащий параметры, переданные в вызываемый метод $name.
Пример #2 Перегрузка методов с помощью методов __call() и __callStatic()
<?php
class MethodTest {
public function __call($name, $arguments) {
// Замечание: значение $name регистрозависимо.
echo "Вызов метода '$name' "
. implode(', ', $arguments). "\n";
}
/** Начиная с версии PHP 5.3.0 */
public static function __callStatic($name, $arguments) {
// Замечание: значение $name регистрозависимо.
echo "Вызов статического метода '$name' "
. implode(', ', $arguments). "\n";
}
}
$obj = new MethodTest;
$obj->runTest('в контексте объекта');
MethodTest::runTest('в статическом контексте'); // Начиная с версии PHP 5.3.0
?>
Результат выполнения данного примера:
Вызов метода 'runTest' в контексте объекта Вызов статического метода 'runTest' в статическом контексте