mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-15 16:38:54 +00:00
508 lines
16 KiB
XML
508 lines
16 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<sect1 xml:id="language.oop5.magic" xmlns="http://docbook.org/ns/docbook">
|
|
<title>Magic Methods</title>
|
|
<para>
|
|
Magic methods are special methods which override PHP's default's action
|
|
when certain actions are performed on an object.
|
|
</para>
|
|
<caution>
|
|
<simpara>
|
|
All methods names starting with <literal>__</literal> are reserved by PHP.
|
|
Therefore, it is not recommended to use such method names unless overriding
|
|
PHP's behavior.
|
|
</simpara>
|
|
</caution>
|
|
<para>
|
|
The following method names are considered magical:
|
|
<!-- Should be an itemized list ? -->
|
|
<link linkend="object.construct">__construct()</link>,
|
|
<link linkend="object.destruct">__destruct()</link>,
|
|
<link linkend="object.call">__call()</link>,
|
|
<link linkend="object.callstatic">__callStatic()</link>,
|
|
<link linkend="object.get">__get()</link>,
|
|
<link linkend="object.set">__set()</link>,
|
|
<link linkend="object.isset">__isset()</link>,
|
|
<link linkend="object.unset">__unset()</link>,
|
|
<link linkend="object.sleep">__sleep()</link>,
|
|
<link linkend="object.wakeup">__wakeup()</link>,
|
|
<link linkend="object.serialize">__serialize()</link>,
|
|
<link linkend="object.unserialize">__unserialize()</link>,
|
|
<link linkend="object.tostring">__toString()</link>,
|
|
<link linkend="object.invoke">__invoke()</link>,
|
|
<link linkend="object.set-state">__set_state()</link>,
|
|
<link linkend="object.clone">__clone()</link>, and
|
|
<link linkend="object.debuginfo">__debugInfo()</link>.
|
|
</para>
|
|
|
|
<warning>
|
|
<!-- See for a code example of this behaviour: https://3v4l.org/Bov34 -->
|
|
<simpara>
|
|
All magic methods, with the exception of
|
|
<link linkend="object.construct">__construct()</link>,
|
|
<link linkend="object.destruct">__destruct()</link>, and
|
|
<link linkend="object.clone">__clone()</link>,
|
|
<emphasis>must</emphasis> be declared as <literal>public</literal>,
|
|
otherwise an <constant>E_WARNING</constant> is emitted.
|
|
Prior to PHP 8.0.0, no diagnostic was emitted for the magic methods
|
|
<link linkend="object.sleep">__sleep()</link>,
|
|
<link linkend="object.wakeup">__wakeup()</link>,
|
|
<link linkend="object.serialize">__serialize()</link>,
|
|
<link linkend="object.unserialize">__unserialize()</link>, and
|
|
<link linkend="object.set-state">__set_state()</link>.
|
|
</simpara>
|
|
</warning>
|
|
<warning>
|
|
<para>
|
|
If type declarations are used in the definition of a magic method, they
|
|
must be identical to the signature described in this document.
|
|
Otherwise, a fatal error is emitted.
|
|
Prior to PHP 8.0.0, no diagnostic was emitted.
|
|
</para>
|
|
</warning>
|
|
|
|
<sect2 xml:id="language.oop5.magic.sleep">
|
|
<title>
|
|
<link linkend="object.sleep">__sleep()</link> and
|
|
<link linkend="object.wakeup">__wakeup()</link>
|
|
</title>
|
|
|
|
<methodsynopsis xml:id="object.sleep">
|
|
<modifier>public</modifier> <type>array</type><methodname>__sleep</methodname>
|
|
<void/>
|
|
</methodsynopsis>
|
|
<methodsynopsis xml:id="object.wakeup">
|
|
<modifier>public</modifier> <type>void</type><methodname>__wakeup</methodname>
|
|
<void/>
|
|
</methodsynopsis>
|
|
|
|
<para>
|
|
<function>serialize</function> checks if the class has a function with
|
|
the magic name <link linkend="object.sleep">__sleep()</link>. If so, that function is
|
|
executed prior to any serialization. It can clean up the object
|
|
and is supposed to return an array with the names of all variables
|
|
of that object that should be serialized.
|
|
If the method doesn't return anything then &null; is serialized and
|
|
<constant>E_NOTICE</constant> is issued.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
It is not possible for <link linkend="object.sleep">__sleep()</link> to return names of
|
|
private properties in parent classes. Doing this will result in an
|
|
<constant>E_NOTICE</constant> level error.
|
|
Use <link linkend="object.serialize">__serialize()</link> instead.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
The intended use of <link linkend="object.sleep">__sleep()</link> is to commit pending
|
|
data or perform similar cleanup tasks. Also, the function is
|
|
useful if a very large objects doesn't need to be saved completely.
|
|
</para>
|
|
<para>
|
|
Conversely, <function>unserialize</function> checks for the
|
|
presence of a function with the magic name
|
|
<link linkend="object.wakeup">__wakeup()</link>. If present, this function can
|
|
reconstruct any resources that the object may have.
|
|
</para>
|
|
<para>
|
|
The intended use of <link linkend="object.wakeup">__wakeup()</link> is to
|
|
reestablish any database connections that may have been lost
|
|
during serialization and perform other reinitialization
|
|
tasks.
|
|
</para>
|
|
<example>
|
|
<title>Sleep and wakeup</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Connection
|
|
{
|
|
protected $link;
|
|
private $dsn, $username, $password;
|
|
|
|
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();
|
|
}
|
|
}?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.oop5.magic.serialize">
|
|
<title>
|
|
<link linkend="object.serialize">__serialize()</link> and
|
|
<link linkend="object.unserialize">__unserialize()</link>
|
|
</title>
|
|
|
|
<methodsynopsis xml:id="object.serialize">
|
|
<modifier>public</modifier> <type>array</type><methodname>__serialize</methodname>
|
|
<void/>
|
|
</methodsynopsis>
|
|
<methodsynopsis xml:id="object.unserialize">
|
|
<modifier>public</modifier> <type>void</type><methodname>__unserialize</methodname>
|
|
<methodparam><type>array</type><parameter>data</parameter></methodparam>
|
|
</methodsynopsis>
|
|
|
|
<para>
|
|
<function>serialize</function> checks if the class has a function with
|
|
the magic name <link linkend="object.serialize">__serialize()</link>. If so, that function is
|
|
executed prior to any serialization. It must construct and return an associative array of key/value pairs
|
|
that represent the serialized form of the object. If no array is returned a <classname>TypeError</classname>
|
|
will be thrown.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
If both <link linkend="object.serialize">__serialize()</link> and <link linkend="object.sleep">__sleep()</link>
|
|
are defined in the same object, only <link linkend="object.serialize">__serialize()</link> will be called.
|
|
<link linkend="object.sleep">__sleep()</link> will be ignored. If the object implements the <link linkend="class.serializable">Serializable</link>
|
|
interface, the interface's <literal>serialize()</literal> method will be ignored and <link linkend="object.serialize">__serialize()</link>
|
|
used instead.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
The intended use of <link linkend="object.serialize">__serialize()</link> is to define a serialization-friendly
|
|
arbitrary representation of the object. Elements of the array may correspond to properties of the object but
|
|
that is not required.
|
|
</para>
|
|
<para>
|
|
Conversely, <function>unserialize</function> checks for the
|
|
presence of a function with the magic name
|
|
<link linkend="object.unserialize">__unserialize()</link>. If present, this function will be passed the
|
|
restored array that was returned from <link linkend="object.serialize">__serialize()</link>. It may
|
|
then restore the properties of the object from that array as appropriate.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
If both <link linkend="object.unserialize">__unserialize()</link> and <link linkend="object.wakeup">__wakeup()</link>
|
|
are defined in the same object, only <link linkend="object.unserialize">__unserialize()</link> will be called.
|
|
<link linkend="object.wakeup">__wakeup()</link> will be ignored.
|
|
</para>
|
|
</note>
|
|
<note>
|
|
<para>
|
|
This feature is available as of PHP 7.4.0.
|
|
</para>
|
|
</note>
|
|
<example>
|
|
<title>Serialize and unserialize</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Connection
|
|
{
|
|
protected $link;
|
|
private $dsn, $username, $password;
|
|
|
|
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 __serialize(): array
|
|
{
|
|
return [
|
|
'dsn' => $this->dsn,
|
|
'user' => $this->username,
|
|
'pass' => $this->password,
|
|
];
|
|
}
|
|
|
|
public function __unserialize(array $data): void
|
|
{
|
|
$this->dsn = $data['dsn'];
|
|
$this->username = $data['user'];
|
|
$this->password = $data['pass'];
|
|
|
|
$this->connect();
|
|
}
|
|
}?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.oop5.magic.tostring">
|
|
<title><link linkend="object.tostring">__toString()</link></title>
|
|
<methodsynopsis xml:id="object.tostring">
|
|
<modifier>public</modifier> <type>string</type><methodname>__toString</methodname>
|
|
<void/>
|
|
</methodsynopsis>
|
|
<para>
|
|
The <link linkend="object.tostring">__toString()</link> method allows a class to decide
|
|
how it will react when it is treated like a string. For example,
|
|
what <literal>echo $obj;</literal> will print.
|
|
</para>
|
|
<warning>
|
|
<para>
|
|
As of PHP 8.0.0, the return value follows standard PHP type semantics,
|
|
meaning it will be coerced into a <type>string</type> if possible and if
|
|
<link linkend="language.types.declarations.strict">strict typing</link>
|
|
is disabled.
|
|
</para>
|
|
<para>
|
|
As of PHP 8.0.0, any class that contains a <link linkend="object.tostring">__toString()</link>
|
|
method will also implicitly implement the <interfacename>Stringable</interfacename> interface, and will
|
|
thus pass type checks for that interface. Explicitly implementing the interface anyway is
|
|
recommended.
|
|
</para>
|
|
<para>
|
|
In PHP 7.4, the returned value <emphasis>must</emphasis> be a
|
|
<type>string</type>, otherwise an <classname>Error</classname> is thrown.
|
|
</para>
|
|
<para>
|
|
Prior to PHP 7.4.0, the returned value <emphasis>must</emphasis> be a
|
|
<type>string</type>, otherwise a fatal <constant>E_RECOVERABLE_ERROR</constant>
|
|
is emitted.
|
|
</para>
|
|
</warning>
|
|
<warning>
|
|
<simpara>
|
|
It was not possible to throw an exception from within a
|
|
<link linkend="object.tostring">__toString()</link>
|
|
method prior to PHP 7.4.0. Doing so will result in a fatal error.
|
|
</simpara>
|
|
</warning>
|
|
<example>
|
|
<title>Simple example</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Declare a simple class
|
|
class TestClass
|
|
{
|
|
public $foo;
|
|
|
|
public function __construct($foo)
|
|
{
|
|
$this->foo = $foo;
|
|
}
|
|
|
|
public function __toString()
|
|
{
|
|
return $this->foo;
|
|
}
|
|
}
|
|
|
|
$class = new TestClass('Hello');
|
|
echo $class;
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Hello
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.oop5.magic.invoke">
|
|
<title><link linkend="object.invoke">__invoke()</link></title>
|
|
<methodsynopsis xml:id="object.invoke">
|
|
<type>mixed</type><methodname>__invoke</methodname>
|
|
<methodparam rep="repeat"><parameter>values</parameter></methodparam>
|
|
</methodsynopsis>
|
|
<para>
|
|
The <link linkend="object.invoke">__invoke()</link> method is called when a script tries to
|
|
call an object as a function.
|
|
</para>
|
|
<example>
|
|
<title>Using <link linkend="object.invoke">__invoke()</link></title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class CallableClass
|
|
{
|
|
public function __invoke($x)
|
|
{
|
|
var_dump($x);
|
|
}
|
|
}
|
|
$obj = new CallableClass;
|
|
$obj(5);
|
|
var_dump(is_callable($obj));
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
int(5)
|
|
bool(true)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.oop5.magic.set-state">
|
|
<title><link linkend="object.set-state">__set_state()</link></title>
|
|
<methodsynopsis xml:id="object.set-state">
|
|
<modifier>static</modifier> <type>object</type><methodname>__set_state</methodname>
|
|
<methodparam><type>array</type><parameter>properties</parameter></methodparam>
|
|
</methodsynopsis>
|
|
<para>
|
|
This <link linkend="language.oop5.static">static</link> method is called
|
|
for classes exported by <function>var_export</function>.
|
|
</para>
|
|
<para>
|
|
The only parameter of this method is an array containing exported
|
|
properties in the form <literal>['property' => value, ...]</literal>.
|
|
</para>
|
|
<example>
|
|
<title>Using <link linkend="object.set-state">__set_state()</link></title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class A
|
|
{
|
|
public $var1;
|
|
public $var2;
|
|
|
|
public static function __set_state($an_array)
|
|
{
|
|
$obj = new A;
|
|
$obj->var1 = $an_array['var1'];
|
|
$obj->var2 = $an_array['var2'];
|
|
return $obj;
|
|
}
|
|
}
|
|
|
|
$a = new A;
|
|
$a->var1 = 5;
|
|
$a->var2 = 'foo';
|
|
|
|
$b = var_export($a, true);
|
|
var_dump($b);
|
|
eval('$c = ' . $b . ';');
|
|
var_dump($c);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
string(60) "A::__set_state(array(
|
|
'var1' => 5,
|
|
'var2' => 'foo',
|
|
))"
|
|
object(A)#2 (2) {
|
|
["var1"]=>
|
|
int(5)
|
|
["var2"]=>
|
|
string(3) "foo"
|
|
}
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<note>
|
|
<simpara>
|
|
When exporting an object, <function>var_export</function> does not check
|
|
whether <link linkend="object.set-state">__set_state()</link> is
|
|
implemented by the object's class, so re-importing such objects will fail,
|
|
if __set_state() is not implemented. Particularly, this affects some
|
|
internal classes.
|
|
</simpara>
|
|
<simpara>
|
|
It is the responsibility of the programmer to verify that only objects will
|
|
be re-imported, whose class implements __set_state().
|
|
</simpara>
|
|
</note>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.oop5.magic.debuginfo">
|
|
<title><link linkend="object.debuginfo">__debugInfo()</link></title>
|
|
<methodsynopsis xml:id="object.debuginfo">
|
|
<type>array</type><methodname>__debugInfo</methodname>
|
|
<void/>
|
|
</methodsynopsis>
|
|
<para>
|
|
This method is called by <function>var_dump</function> when dumping an
|
|
object to get the properties that should be shown. If the method isn't
|
|
defined on an object, then all public, protected and private properties
|
|
will be shown.
|
|
</para>
|
|
<example>
|
|
<title>Using <link linkend="object.debuginfo">__debugInfo()</link></title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class C {
|
|
private $prop;
|
|
|
|
public function __construct($val) {
|
|
$this->prop = $val;
|
|
}
|
|
|
|
public function __debugInfo() {
|
|
return [
|
|
'propSquared' => $this->prop ** 2,
|
|
];
|
|
}
|
|
}
|
|
|
|
var_dump(new C(42));
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
object(C)#1 (1) {
|
|
["propSquared"]=>
|
|
int(1764)
|
|
}
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</sect2>
|
|
</sect1>
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|