Магические методы
Имена методов __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() и __debugInfo() зарезервированы для «магических» методов в PHP. Не стоит называть свои методы этими именами, если вы не хотите использовать их «магическую» функциональность.
PHP оставляет за собой право все методы, начинающиеся с __, считать «магическими». Не рекомендуется использовать имена методов с __ в PHP, если вы не желаете использовать соответствующий «магический» функционал.
__sleep() и __wakeup()
Функция serialize() проверяет, присутствует ли в вашем классе метод с «магическим» именем __sleep(). Если это так, то этот метод выполняется прежде любой операции сериализации. Он может очистить объект и предполагается, что будет возвращен массив с именами всех переменных объекта, который должен быть сериализован. Если метод ничего не возвращает кроме NULL , то это значит, что объект сериализован и выдается предупреждение E_NOTICE .
Замечание:
Недопустимо возвращать в __sleep() имена приватных свойств объекта в родительский класс. Это приведет к предупреждению E_NOTICE . Вместо этого вы можете использовать интерфейс Serializable.
Рекомендованное использование __sleep() состоит в завершении работы над данными, ждущими обработки или других подобных задач очистки. Кроме того, этот метод можно выполнять в тех случаях, когда нет необходимости сохранять полностью очень большие объекты.
С другой стороны, функция unserialize() проверяет наличие метода с «магическим» именем __wakeup(). Если такой имеется, то он может воссоздать все ресурсы объекта, принадлежавшие ему.
Обычно __wakeup() используется для восстановления любых соединений с базой данных, которые могли быть потеряны во время операции сериализации и выполнения других операций повторной инициализации.
Пример #1 Sleep и wakeup
class Connection
protected $link ;
private $dsn , $username , $password ;
?php
public function __construct ( $dsn , $username , $password )
$this -> dsn = $dsn ;
$this -> username = $username ;
$this -> password = $password ;
$this -> connect ();
>
private function connect ()
$this -> link = new PDO ( $this -> dsn , $this -> username , $this -> password );
>
public function __sleep ()
return array( ‘dsn’ , ‘username’ , ‘password’ );
>
public function __wakeup ()
$this -> connect ();
>
> ?>
__toString()
Метод __toString() позволяет классу решать самостоятельно, как он должен реагировать при преобразовании в строку. Например, что напечатает echo $obj;. Этот метод должен возвращать строку, иначе выдастся неисправимая ошибка E_RECOVERABLE_ERROR .
Нельзя бросить исключение из метода __toString(). Попытка это сделать закончится фатальной ошибкой.
Пример #2 Простой пример
// Объявление простого класса
class TestClass
public $foo ;
?php
public function __construct ( $foo )
$this -> foo = $foo ;
>
public function __toString ()
return $this -> foo ;
>
>
$class = new TestClass ( ‘Привет’ );
echo $class ;
?>
Результат выполнения данного примера:
Ранее, до PHP 5.2.0, метод __toString() вызывался только непосредственно в сочетании с функциями echo или print . Начиная с PHP 5.2.0, он вызывается в любом строчном контексте (например, в printf() с модификатором %s), но не в контекстах других типов (например, с %d модификатором). Начиная с PHP 5.2.0, преобразование объекта в строку при отсутствии метода __toString() вызывает ошибку E_RECOVERABLE_ERROR .
__invoke()
Метод __invoke() вызывается, когда скрипт пытается выполнить объект как функцию.
Замечание:
Данный метод доступен начиная с PHP 5.3.0.
Пример #3 Использование __invoke()
class CallableClass
public function __invoke ( $x )
var_dump ( $x );
>
>
$obj = new CallableClass ;
$obj ( 5 );
var_dump ( is_callable ( $obj ));
?>?php
Результат выполнения данного примера:
__set_state()
Этот статический метод вызывается для тех классов, которые экспортируются функцией var_export() начиная с PHP 5.1.0.
Параметр этого метода должен содержать массив, состоящий из экспортируемых свойств в виде array(‘property’ => value, . ).
Пример #4 Использование __set_state() (начиная с PHP 5.1.0)
class A
public $var1 ;
public $var2 ;
public static function __set_state ( $an_array ) // С PHP 5.1.0
$obj = new A ;
$obj -> var1 = $an_array [ ‘var1’ ];
$obj -> var2 = $an_array [ ‘var2’ ];
return $obj ;
>
>
$a = new A ;
$a -> var1 = 5 ;
$a -> var2 = ‘foo’ ;
eval( ‘$b = ‘ . var_export ( $a , true ) . ‘;’ ); // $b = A::__set_state(array(
// ‘var1’ => 5,
// ‘var2’ => ‘foo’,
// ));
var_dump ( $b );
Результат выполнения данного примера:
object(A)#2 (2) < ["var1"]=>int(5) ["var2"]=> string(3) "foo" >
__debugInfo()
Этот метод вызывается функцией var_dump() , когда необходимо вывести список свойств объекта. Если этот метод не определен, тогда будут выведены все public, protected и private свойства объекта.
Этот метод был добавлен в PHP 5.6.0.
Пример #5 Использование __debugInfo()
public function __construct ( $val ) $this -> prop = $val ;
>
public function __debugInfo () return [
‘propSquared’ => $this -> prop ** 2 ,
];
>
>
Результат выполнения данного примера:
PHP RFC: __toArray()
This RFC proposes to add a new magic method called __toArray() to allow a class to control how it is represented when converted to an array.
PHP contains many magic methods that give a class greater control over its interaction with the language. The methods __serialize() and __unserialize() give a class control over how it is serialized, __clone() allows control over how self copies are made, and __toString() allows a class to control how it is represented when converted to a string. Adding a __toArray() method gives developers the ability to transform a class to an array in similar fashion.
Proposal
class Person { protected $name; protected $email; public $foo = 'bar'; public function __construct(string $name, string $email) { $this->name = $name; $this->email = $email; } public function __toArray() { return [ 'name' => $this->name, 'email' => $this->email, ]; } } $person = new Person('John Doe', 'j.doe@example.com');
$personArray = (array) $person; // casting triggers __toArray()
What this is
The example above shows the method __toArray() used in a type-casting context. This proposal would have objects implementing the __toArray() magic method called within any array context including type hinting and return types (only when using weak typing — strong typing will throw an error).
Similar to PHP’s current implementation of __toString(), a copy of the given object’s value as an array is made upon conversion.
Type Hinting
function foo(array $person) { var_dump($person); } // Output /* array(2) < ["name"]=>string(8) "John Doe" ["email"]=> string(17) "j.doe@example.com" > */
Return Type
function bar(Person $person): array { return $person; } var_dump(bar($person)); // Output /* array(2) < ["name"]=>string(8) "John Doe" ["email"]=> string(17) "j.doe@example.com" > */
array_* and built-in functions
The array operating functions listed on the Array Functions would first convert an object implementing the __toArray() method before continuing operations.
print_r( array_keys($person) ); // Output /* Array ( [0] => first [1] => email ) */
Strict Types
Automatic casting will not work when using strict types.
declare(strict_types=1); function bar(Person $person): array { return $person; } bar($person); // Throws an error: "Return value of bar() must be of the type array, object returned" function foo(array $person) { var_dump($person); } foo($person); // Throws an error: "Argument 1 passed to foo() must be of the type array, object given"
Manual casting within strict types will continue to work and is allowed.
declare(strict_types=1); function bar(Person $person): array { return (array) $person; } bar($person); // Returns an array function foo(array $person) { var_dump($person); } foo((array) $person); // Allowed
What this is not
This proposal does not allow accessing and setting values as you would in a normal array, that functionality remains with classes implementing the ArrayAccess interface.
Array functions that operate on an array by reference such as sort or shuffle will not work on an object implementing __toArray() under this proposal.
php RFC:__toArray()
Calling any objects implemented __toArray() magic method on any array context including type hinting(only when using weak typing) and return types can get array version of the object.
Usage
function foo(array $person) print_r($person); > // Output /* [ "name" => "John Doe" "email"=> "jon@example.com" > */
function bar(Person $person): array return $person; > print_r(bar($person)); // Output /* [ "name" =>"John Doe" "email"=>"jon@example.com" ] */
declare(strict_types=1); function bar(Person $person): array return (array) $person; > /* [ "name" =>"John Doe" "email"=>"jon@example.com" ] */ // Note: without the array type casting before return would trigger an error here.
This is similar to PHP’s current implementation of __toString(),
a copy of the given object’s value as an array
is made upon conversion. However this proposal does not allow accessing and setting values as you would in a normal array, that functionality remains with classes implementing the ArrayAccess interface. For more information take a look at the RFC