Перегрузка в PHP означает возможность динамически создавать
свойства и методы. Эти динамические сущности обрабатываются с
помощью магических методов, которые можно создать в классе для
различных видов действий.
Методы перегрузки вызываются при взаимодействии со свойствами
или методами, которые не были объявлены или не видны в текущей области
видимости. Далее в этом разделе будут использоваться термины
недоступные свойства
или недоступные методы
для обозначения этой комбинации объявления и области видимости.
Все методы перегрузки должны быть объявлены как public
.
Замечание:
Ни один из аргументов этих магических методов не может быть передан по ссылке.
Замечание:
Интерпретация
перегрузкив PHP отличается от большинства объектно-ориентированных языков. Традиционно перегрузка означает возможность иметь несколько одноимённых методов с разным количеством и типами аргументов.
$name
): bool$name
): voidМетод __set() будет выполнен при записи данных в недоступные (защищённые или приватные) или несуществующие свойства.
Метод __get() будет выполнен при чтении данных из недоступных (защищённых или приватных) или несуществующих свойств.
Метод __isset() будет выполнен при использовании isset() или empty() на недоступных (защищённых или приватных) или несуществующих свойствах.
Метод __unset() будет выполнен при вызове unset() на недоступном (защищённом или приватном) или несуществующем свойстве.
Аргумент $name представляет собой имя вызываемого свойства. Метод __set() содержит аргумент $value, представляющий собой значение, которое будет записано в свойство с именем $name.
Перегрузка свойств работает только в контексте объекта.
Данные магические методы не будут вызваны в статическом контексте.
Поэтому эти методы не должны объявляться
статическими.
При объявлении любого магического метода как
static
будет выдано предупреждение.
Замечание:
Возвращаемое значение __set() будет проигнорировано из-за способа обработки в PHP оператора присваивания. Аналогично, __get() никогда не вызывается при объединении присваиваний, например, подобным образом:
$a = $obj->b = 8;
Замечание:
PHP не будет вызывать перегруженный метод изнутри того же перегруженного метода. Это означает, что, например, написание
return $this->foo
внутри __get() вернётnull
и вызовет ошибку уровняE_WARNING
, если не определено свойствоfoo
, вместо того, чтобы вызвать метод __get() во второй раз. Однако методы перегрузки могут неявно вызывать другие методы перегрузки (например, метод __set() вызывает метод __get()).
Пример #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;
}
public function __isset($name)
{
echo "Установлено ли '$name'?\n";
return isset($this->data[$name]);
}
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 "Давайте поэкспериментируем с закрытым свойством 'hidden':\n";
echo "Закрытые свойства видны внутри класса, поэтому __get() не используется...\n";
echo $obj->getHidden() . "\n";
echo "Закрытые свойства не видны вне класса, поэтому __get() используется...\n";
echo $obj->hidden . "\n";
?>
Результат выполнения данного примера:
Установка 'a' в '1' Получение 'a' 1 Установлено ли 'a'? bool(true) Уничтожение 'a' Установлено ли 'a'? bool(false) 1 Давайте поэкспериментируем с закрытым свойством 'hidden': Закрытые свойства видны внутри класса, поэтому __get() не используется... 2 Закрытые свойства не видны вне класса, поэтому __get() используется... Получение 'hidden' Notice: Неопределённое свойство в __get(): hidden в <file> on line 70 in <file> on line 29
__call() запускается при вызове недоступных методов в контексте объект.
__callStatic() запускается при вызове недоступных методов в статическом контексте.
Аргумент $name представляет собой имя вызываемого метода. Аргумент $arguments представляет собой нумерованный массив, содержащий параметры, переданные в вызываемый метод $name.
Пример #2 Перегрузка методов с помощью методов __call() и __callStatic()
<?php
class MethodTest {
public function __call($name, $arguments) {
// Замечание: значение $name регистрозависимо.
echo "Вызов метода '$name' "
. implode(', ', $arguments). "\n";
}
public static function __callStatic($name, $arguments) {
// Замечание: значение $name регистрозависимо.
echo "Вызов статического метода '$name' "
. implode(', ', $arguments). "\n";
}
}
$obj = new MethodTest;
$obj->runTest('в контексте объекта');
MethodTest::runTest('в статическом контексте');
?>
Результат выполнения данного примера:
Вызов метода 'runTest' в контексте объекта Вызов статического метода 'runTest' в статическом контексте