Перегрузка

Перегрузка в PHP означает возможность динамически создавать свойства и методы. Эти динамические сущности обрабатываются с помощью магических методов, которые можно создать в классе для различных видов действий.

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

Все методы перегрузки должны быть объявлены как public.

Замечание:

Ни один из аргументов этих магических методов не может быть передан по ссылке.

Замечание:

Интерпретация перегрузки в PHP отличается от большинства объектно-ориентированных языков. Традиционно перегрузка означает возможность иметь несколько одноимённых методов с разным количеством и типами аргументов.

Перегрузка свойств

public__set(string$name, mixed$value): void
public__get(string$name): mixed
public__isset(string$name): bool
public__unset(string$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 

Перегрузка методов

public__call(string$name, array$arguments): mixed
public static__callStatic(string$name, array$arguments): mixed

__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' в статическом контексте 
To Top