Перегрузка

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

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

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

Замечание:

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

Замечание:

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

Список изменений

Версия Описание
5.3.0 Добавлен метод __callStatic(). Добавлено предупреждение об усилении публичной видимости и не-статичном объявлении.
5.1.0 Добавлены методы __isset() и __unset().

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

public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )

Метод __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->1;
echo 
$obj->"\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

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

public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )

В контексте объекта при вызове недоступных методов вызывается метод __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' в статическом контексте

Участник рейтинга Тэглайн 2010