mirror of
https://github.com/php/doc-en.git
synced 2026-03-23 23:32:18 +01:00
289 lines
6.1 KiB
XML
289 lines
6.1 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<sect1 xml:id="language.oop5.late-static-bindings" xmlns="http://docbook.org/ns/docbook">
|
|
<title>Late Static Bindings</title>
|
|
<para>
|
|
PHP implements a feature called late static bindings which
|
|
can be used to reference the called class in a context of static inheritance.
|
|
</para>
|
|
|
|
<para>
|
|
More precisely, late static bindings work by storing the class named in the
|
|
last "non-forwarding call". In case of static method calls, this is the
|
|
class explicitly named (usually the one on the left of the
|
|
<link linkend="language.oop5.paamayim-nekudotayim"><literal>::</literal></link>
|
|
operator); in case of non static method calls, it is the class of the object. A
|
|
"forwarding call" is a static one that is introduced by <literal>self::</literal>,
|
|
<literal>parent::</literal>, <literal>static::</literal>, or, if going
|
|
up in the class hierarchy, <function>forward_static_call</function>.
|
|
<!-- technically, static:: may be non forwarding, but it's irrelevant -->
|
|
|
|
The function <function>get_called_class</function> can be used to retrieve
|
|
a string with the name of the called class and <literal>static::</literal>
|
|
introduces its scope.
|
|
</para>
|
|
|
|
<para>
|
|
This feature was named "late static bindings" with an internal perspective in
|
|
mind. "Late binding" comes from the fact that <literal>static::</literal>
|
|
will not be resolved using the class where the method is defined but it will
|
|
rather be computed using runtime information.
|
|
|
|
It was also called a "static binding" as it can be used for (but is not
|
|
limited to) static method calls.
|
|
</para>
|
|
|
|
<sect2 xml:id="language.oop5.late-static-bindings.self">
|
|
<title>Limitations of <literal>self::</literal></title>
|
|
<para>
|
|
Static references to the current class like <literal>self::</literal> or
|
|
<literal>__CLASS__</literal> are resolved using the class in which the
|
|
function belongs, as in where it was defined:
|
|
</para>
|
|
<example>
|
|
<title><literal>self::</literal> usage</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class A
|
|
{
|
|
public static function who()
|
|
{
|
|
echo __CLASS__;
|
|
}
|
|
|
|
public static function test()
|
|
{
|
|
self::who();
|
|
}
|
|
}
|
|
|
|
class B extends A
|
|
{
|
|
public static function who()
|
|
{
|
|
echo __CLASS__;
|
|
}
|
|
}
|
|
|
|
B::test();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
A
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="language.oop5.late-static-bindings.usage">
|
|
<title>Late Static Bindings' usage</title>
|
|
|
|
<para>
|
|
Late static bindings tries to solve that limitation by introducing a
|
|
keyword that references the class that was initially called at runtime.
|
|
Basically, a keyword that would allow referencing
|
|
<literal>B</literal> from <literal>test()</literal> in the previous
|
|
example. It was decided not to introduce a new keyword but rather use
|
|
<literal>static</literal> that was already reserved.
|
|
</para>
|
|
|
|
<example>
|
|
<title><literal>static::</literal> simple usage</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class A
|
|
{
|
|
public static function who()
|
|
{
|
|
echo __CLASS__;
|
|
}
|
|
|
|
public static function test()
|
|
{
|
|
static::who(); // Here comes Late Static Bindings
|
|
}
|
|
}
|
|
|
|
class B extends A
|
|
{
|
|
public static function who()
|
|
{
|
|
echo __CLASS__;
|
|
}
|
|
}
|
|
|
|
B::test();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
B
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<note>
|
|
<para>
|
|
In non-static contexts, the called class will be the class of the object
|
|
instance. Since <literal>$this-></literal> will try to call private
|
|
methods from the same scope, using <literal>static::</literal> may give
|
|
different results. Another difference is that <literal>static::</literal>
|
|
can only refer to static properties.
|
|
</para>
|
|
</note>
|
|
<example>
|
|
<title><literal>static::</literal> usage in a non-static context</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class A
|
|
{
|
|
private function foo()
|
|
{
|
|
echo "Success!\n";
|
|
}
|
|
|
|
public function test()
|
|
{
|
|
$this->foo();
|
|
static::foo();
|
|
}
|
|
}
|
|
|
|
class B extends A
|
|
{
|
|
/* foo() will be copied to B, hence its scope will still be A and
|
|
* the call be successful */
|
|
}
|
|
|
|
class C extends A
|
|
{
|
|
private function foo()
|
|
{
|
|
/* Original method is replaced; the scope of the new one is C */
|
|
}
|
|
}
|
|
|
|
$b = new B();
|
|
$b->test();
|
|
|
|
$c = new C();
|
|
try {
|
|
$c->test();
|
|
} catch (Error $e) {
|
|
echo $e->getMessage();
|
|
}
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Success!
|
|
Success!
|
|
Success!
|
|
Call to private method C::foo() from scope A
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<note>
|
|
<para>
|
|
Late static bindings' resolution will stop at a fully resolved static call
|
|
with no fallback. On the other hand, static calls using keywords like
|
|
<literal>parent::</literal> or <literal>self::</literal> will forward the
|
|
calling information.
|
|
</para>
|
|
<example>
|
|
<title>Forwarding and non-forwarding calls</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class A
|
|
{
|
|
public static function foo()
|
|
{
|
|
static::who();
|
|
}
|
|
|
|
public static function who()
|
|
{
|
|
echo __CLASS__ . "\n";
|
|
}
|
|
}
|
|
|
|
class B extends A
|
|
{
|
|
public static function test()
|
|
{
|
|
A::foo();
|
|
parent::foo();
|
|
self::foo();
|
|
}
|
|
|
|
public static function who()
|
|
{
|
|
echo __CLASS__ . "\n";
|
|
}
|
|
}
|
|
|
|
class C extends B
|
|
{
|
|
public static function who()
|
|
{
|
|
echo __CLASS__ . "\n";
|
|
}
|
|
}
|
|
|
|
C::test();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
A
|
|
C
|
|
C
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</note>
|
|
</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
|
|
-->
|
|
|