php-doc-en/language/oop5/late-static-bindings.xml
George Peter Banyard 9ee9eccf45 Refactor OO section part 2
Some misses from the first time

Signed-off-by: Larry Garfield <larry@garfieldtech.com>

Closes GH-329
2021-03-04 17:06:22 -06:00

249 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();
$c->test(); //fails
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
success!
success!
success!
Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
]]>
</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
-->