Перегрузка

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

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

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

Замечание:

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

Замечание:

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

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

Версия Описание
5.3.0 Добавлен метод __callStatic(). Добавлено предупреждение об усилении общедоступной видимости и нестатичном объявлении.
5.1.0 Добавлены методы __isset() и __unset(). Добавлена поддержка для перегрузки закрытых свойств с помощью __get().
5.0.0 Добавлен метод __get().

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

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.

Перегрузка свойств работает только в контексте объекта. Данные магические методы не будут вызваны в статическом контексте. Поэтому эти методы не должны объявляться статическими. Начиная с версии PHP 5.3.0, при объявлении любого магического метода как static будет выдано предупреждение.

Замечание:

Возвращаемое значение __set() будет проигнорировано из-за способа обработки в PHP оператора присваивания. Аналогично, __get() никогда не вызывается при объединении присваиваний, например, подобным образом:

 $a = $obj->b = 8; 

Пример #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 
"Давайте поэкспериментируем с закрытым свойством '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";
    }

    
/**  Начиная с 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' в статическом контексте