mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-15 08:28:54 +00:00

Some misses from the first time Signed-off-by: Larry Garfield <larry@garfieldtech.com> Closes GH-329
249 lines
6.1 KiB
XML
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
|
|
-->
|
|
|