Source of: /manual/en/language.oop5.late-static-bindings.php
<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/language.oop5.inc";
$setup = array (
'home' =>
array (
0 => 'index.php',
1 => 'PHP Manual',
),
'head' =>
array (
0 => 'UTF-8',
1 => 'en',
),
'this' =>
array (
0 => 'language.oop5.late-static-bindings.php',
1 => 'Late Static Bindings',
),
'up' =>
array (
0 => 'language.oop5.php',
1 => 'Classes and Objects',
),
'prev' =>
array (
0 => 'language.oop5.typehinting.php',
1 => 'Type Hinting',
),
'next' =>
array (
0 => 'language.oop5.references.php',
1 => 'Objects and references',
),
);
$setup["toc"] = $TOC;
$setup["parents"] = $PARENTS;
manual_setup($setup);
manual_header();
?>
<div id="language.oop5.late-static-bindings" class="sect1">
<h2 class="title">Late Static Bindings</h2>
<p class="para">
As of PHP 5.3.0, PHP implements a feature called late static bindings which
can be used to reference the called class in a context of static inheritance.
</p>
<p class="para">
This feature was named "late static bindings" with an internal perspective in
mind. "Late binding" comes from the fact that <i>static::</i>
will no longer 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.
</p>
<div id="language.oop5.late-static-bindings.self" class="sect2">
<h3 class="title">Limitations of <i>self::</i></h3>
<p class="para">
Static references to the current class like <i>self::</i> or
<i>__CLASS__</i> are resolved using the class in which the
function belongs, as in where it was defined:
</p>
<div class="example">
<p><b>Example #1 <i>self::</i> usage</b></p>
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">;<br /> }<br /> public static function </span><span style="color: #0000BB">test</span><span style="color: #007700">() {<br /> </span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">who</span><span style="color: #007700">();<br /> }<br />}<br /><br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">;<br /> }<br />}<br /><br /></span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">test</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<div class="example-contents para"><p>The above example will output:</p></div>
<div class="example-contents screen">
<div class="cdata"><pre>
A
</pre></div>
</div>
</div>
</div>
<div id="language.oop5.late-static-bindings.usage" class="sect2">
<h3 class="title">Late Static Bindings' usage</h3>
<p class="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 you to reference
<i>B</i> from <i>test()</i> in the previous
example. It was decided not to introduce a new keyword but rather use
<i>static</i> that was already reserved.
</p>
<div class="example">
<p><b>Example #2 <i>static::</i> simple usage</b></p>
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">;<br /> }<br /> public static function </span><span style="color: #0000BB">test</span><span style="color: #007700">() {<br /> static::</span><span style="color: #0000BB">who</span><span style="color: #007700">(); </span><span style="color: #FF8000">// Here comes Late Static Bindings<br /> </span><span style="color: #007700">}<br />}<br /><br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">;<br /> }<br />}<br /><br /></span><span style="color: #0000BB">B</span><span style="color: #007700">::</span><span style="color: #0000BB">test</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<div class="example-contents para"><p>The above example will output:</p></div>
<div class="example-contents screen">
<div class="cdata"><pre>
B
</pre></div>
</div>
</div>
<blockquote><p><b class="note">Note</b>:
<i>static::</i> does not work like <i>$this</i> for
static methods! <i>$this-></i> follows the rules of
inheritance while <i>static::</i> doesn't. This difference is
detailed later on this manual page.
<br />
</p></blockquote>
<div class="example">
<p><b>Example #3 <i>static::</i> usage in a non-static context</b></p>
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">TestChild </span><span style="color: #007700">extends </span><span style="color: #0000BB">TestParent </span><span style="color: #007700">{<br /> public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">() {<br /> static::</span><span style="color: #0000BB">who</span><span style="color: #007700">();<br /> }<br /><br /> public function </span><span style="color: #0000BB">test</span><span style="color: #007700">() {<br /> </span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">TestParent</span><span style="color: #007700">();<br /> }<br /><br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br />}<br /><br />class </span><span style="color: #0000BB">TestParent </span><span style="color: #007700">{<br /> public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">() {<br /> static::</span><span style="color: #0000BB">who</span><span style="color: #007700">();<br /> }<br /><br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br />}<br /></span><span style="color: #0000BB">$o </span><span style="color: #007700">= new </span><span style="color: #0000BB">TestChild</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$o</span><span style="color: #007700">-></span><span style="color: #0000BB">test</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<div class="example-contents para"><p>The above example will output:</p></div>
<div class="example-contents screen">
<div class="cdata"><pre>
TestChild
TestParent
</pre></div>
</div>
</div>
<blockquote><p><b class="note">Note</b>:
Late static bindings' resolution will stop at a fully resolved static call
with no fallback. On the other hand, static calls using keywords like
<i>parent::</i> or <i>self::</i> will forward the
calling information.
<br />
</p><div class="example">
<p><b>Example #4 Forwarding and non-forwarding calls</b></p>
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">foo</span><span style="color: #007700">() {<br /> static::</span><span style="color: #0000BB">who</span><span style="color: #007700">();<br /> }<br /><br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br />}<br /><br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">test</span><span style="color: #007700">() {<br /> </span><span style="color: #0000BB">A</span><span style="color: #007700">::</span><span style="color: #0000BB">foo</span><span style="color: #007700">();<br /> </span><span style="color: #0000BB">parent</span><span style="color: #007700">::</span><span style="color: #0000BB">foo</span><span style="color: #007700">();<br /> </span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">foo</span><span style="color: #007700">();<br /> }<br /><br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br />}<br />class </span><span style="color: #0000BB">C </span><span style="color: #007700">extends </span><span style="color: #0000BB">B </span><span style="color: #007700">{<br /> public static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br />}<br /><br /></span><span style="color: #0000BB">C</span><span style="color: #007700">::</span><span style="color: #0000BB">test</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<div class="example-contents para"><p>The above example will output:</p></div>
<div class="example-contents screen">
<div class="cdata"><pre>
A
C
C
</pre></div>
</div>
</div><p>
</p></blockquote>
</div>
<div id="language.oop5.late-static-bindings.edge-cases" class="sect2">
<h3 class="title">Edge cases</h3>
<p class="para">
There are lots of different ways to trigger a method call in PHP, like
callbacks or magic methods. As late static bindings base their resolution
on runtime information, it might give unexpected results in so-called edge
cases.
</p>
<div class="example">
<p><b>Example #5 Late static bindings inside magic methods</b></p>
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /><br /> protected static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br /><br /> public function </span><span style="color: #0000BB">__get</span><span style="color: #007700">(</span><span style="color: #0000BB">$var</span><span style="color: #007700">) {<br /> return static::</span><span style="color: #0000BB">who</span><span style="color: #007700">();<br /> }<br />}<br /><br />class </span><span style="color: #0000BB">B </span><span style="color: #007700">extends </span><span style="color: #0000BB">A </span><span style="color: #007700">{<br /><br /> protected static function </span><span style="color: #0000BB">who</span><span style="color: #007700">() {<br /> echo </span><span style="color: #0000BB">__CLASS__</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /> }<br />}<br /><br /></span><span style="color: #0000BB">$b </span><span style="color: #007700">= new </span><span style="color: #0000BB">B</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$b</span><span style="color: #007700">-></span><span style="color: #0000BB">foo</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<div class="example-contents para"><p>The above example will output:</p></div>
<div class="example-contents screen">
<div class="cdata"><pre>
B
</pre></div>
</div>
</div>
</div>
</div><?php manual_footer(); ?>