Source of: /manual/en/migration51.references.php
<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/migration51.inc";
$setup = array (
'home' =>
array (
0 => 'index.php',
1 => 'PHP Manual',
),
'head' =>
array (
0 => 'UTF-8',
1 => 'en',
),
'this' =>
array (
0 => 'migration51.references.php',
1 => 'Changes in reference handling',
),
'up' =>
array (
0 => 'migration51.php',
1 => 'Migrating from PHP 5.0.x to PHP 5.1.x',
),
'prev' =>
array (
0 => 'migration51.changes.php',
1 => 'Key PHP 5.1.x features',
),
'next' =>
array (
0 => 'migration51.reading.php',
1 => 'Reading []',
),
);
$setup["toc"] = $TOC;
$setup["parents"] = $PARENTS;
manual_setup($setup);
manual_header();
?>
<div id="migration51.references" class="section">
<h2 class="title">Changes in reference handling</h2>
<ul class="itemizedlist">
<li class="listitem">
<p class="para">
<a href="migration51.references.php#migration51.references-overview" class="link">Overview</a>
</p>
</li>
<li class="listitem">
<p class="para">
<a href="migration51.references.php#migration51.references-fails" class="link">Code that worked under PHP
4.3.x, but now fails</a>
</p>
</li>
<li class="listitem">
<p class="para">
<a href="migration51.references.php#migration51.references-error" class="link">Code that worked under PHP
4.3.x, but now throws an error</a>
</p>
</li>
<li class="listitem">
<p class="para">
<a href="migration51.references.php#migration51.references-works" class="link">Code that failed under PHP
4.3.x, but now works</a>
</p>
</li>
<li class="listitem">
<p class="para">
<a href="migration51.references.php#migration51.references-didnotwork" class="link">Code that
<i>should have worked</i> under PHP 5.0.x</a>
</p>
</li>
<li class="listitem">
<p class="para">
<a href="migration51.references.php#migration51.references-warnings" class="link">Warnings that came and
went</a>
</p>
</li>
</ul>
<div id="migration51.references-overview" class="section">
<h2 class="title">Overview</h2>
<p class="para">
From the PHP script writer's point of view, the change most likely to
impact legacy code is in the way that references are handled in all PHP
versions post-dating the PHP 4.4.0 release.
</p>
<p class="para">
Until and including PHP 4.3, it was possible to send, assign or return
variables by reference that should really be returned by value, such as
a constant, a temporary value (e.g. the result of an expression), or the
result of a function that had itself been returned by value, as here:
</p>
<div class="informalexample">
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br />$foo </span><span style="color: #007700">= </span><span style="color: #DD0000">"123"</span><span style="color: #007700">;<br /><br />function </span><span style="color: #0000BB">return_value</span><span style="color: #007700">() {<br /> global </span><span style="color: #0000BB">$foo</span><span style="color: #007700">;<br /> return </span><span style="color: #0000BB">$foo</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$bar </span><span style="color: #007700">= &</span><span style="color: #0000BB">return_value</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
</div>
<p class="para">
Although this code would usually work as expected under PHP 4.3, in the
general case the result is undefined. The Zend Engine could not act
correctly on these values as references. This bug could and did lead to
various hard-to-reproduce memory corruption problems, particularly
where the code base was large.
</p>
<p class="para">
In PHP 4.4.0, PHP 5.0.4 and all subsequent PHP releases, the Engine was
fixed to 'know' when the reference operation is being used on a value
that should not be referenced. The actual value is now used in such
cases, and a warning is emitted. The warning takes the form of an
<b><tt class="constant">E_NOTICE</tt></b> in PHP 4.4.0 and up, and
<b><tt class="constant">E_STRICT</tt></b> in PHP 5.0.4 and up.
</p>
<p class="para">
Code that could potentially produce memory corruption can no longer do
so. However, some legacy code might work differently as a result.
</p>
</div>
<div id="migration51.references-fails" class="section">
<h2 class="title">Code that worked under PHP 4.3, but now fails</h2>
<div class="informalexample">
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">func</span><span style="color: #007700">(&</span><span style="color: #0000BB">$arraykey</span><span style="color: #007700">) {<br /> return </span><span style="color: #0000BB">$arraykey</span><span style="color: #007700">; </span><span style="color: #FF8000">// function returns by value!<br /></span><span style="color: #007700">}<br /><br /></span><span style="color: #0000BB">$array </span><span style="color: #007700">= array(</span><span style="color: #DD0000">'a'</span><span style="color: #007700">, </span><span style="color: #DD0000">'b'</span><span style="color: #007700">, </span><span style="color: #DD0000">'c'</span><span style="color: #007700">);<br />foreach (</span><span style="color: #0000BB">array_keys</span><span style="color: #007700">(</span><span style="color: #0000BB">$array</span><span style="color: #007700">) as </span><span style="color: #0000BB">$key</span><span style="color: #007700">) {<br /> </span><span style="color: #0000BB">$y </span><span style="color: #007700">= &</span><span style="color: #0000BB">func</span><span style="color: #007700">(</span><span style="color: #0000BB">$array</span><span style="color: #007700">[</span><span style="color: #0000BB">$key</span><span style="color: #007700">]);<br /> </span><span style="color: #0000BB">$z</span><span style="color: #007700">[] =& </span><span style="color: #0000BB">$y</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">$z</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?><br /></span><</span>
</code></div>
</div>
<p class="para">
Running the above script under any version of PHP that pre-dates the
reference fix would produce this output:
</p>
<div class="example-contents screen">
<div class="cdata"><pre>
array(3) {
[0]=>
&string(1) "a"
[1]=>
&string(1) "b"
[2]=>
&string(1) "c"
}
</pre></div>
</div>
<p class="para">
Following the reference fix, the same code would result in:
</p>
<div class="example-contents screen">
<div class="cdata"><pre>
array(3) {
[0]=>
&string(1) "c"
[1]=>
&string(1) "c"
[2]=>
&string(1) "c"
}
</pre></div>
</div>
</div>
<p class="para">
This is because, following the changes, <i>func()</i>
assigns by value. The value of <var class="varname">$y</var> is re-assigned,
and reference-binding is preserved from <var class="varname">$z</var>. Prior to
the fix, the value was assigned by reference, leading <var class="varname">$y</var>
to be re-bound on each assignment. The attempt to bind to a temporary
value by reference was the cause of the memory corruption.
</p>
<p class="para">
Such code can be made to work identically in both the pre-fix and the
post-fix PHP versions. The signature of <i>func()</i> can
be altered to return by reference, or the reference assignment can be
removed from the result of <i>func()</i>.
</p>
<div class="informalexample">
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">function </span><span style="color: #0000BB">func</span><span style="color: #007700">() {<br /> return </span><span style="color: #DD0000">'function return'</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$x </span><span style="color: #007700">= </span><span style="color: #DD0000">'original value'</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$y </span><span style="color: #007700">=& </span><span style="color: #0000BB">$x</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$y </span><span style="color: #007700">= &</span><span style="color: #0000BB">func</span><span style="color: #007700">();<br />echo </span><span style="color: #0000BB">$x</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
</div>
<p class="para">
In PHP 4.3 <var class="varname">$x</var> would be 'original value', whereas after
the changes it would be 'function return' - remember that where the
function does not return by reference, the reference assignment is
converted to a regular assignment. Again, this can be brought to a common
base, either by forcing <i>func()</i> to return by reference
or by eliminating the by-reference assignment.
</p>
</div>
<div id="migration51.references-error" class="section">
<h2 class="title">Code that worked under PHP 4.3.x, but now throws an error</h2>
<div class="informalexample">
<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">Foo </span><span style="color: #007700">{<br /><br /> function </span><span style="color: #0000BB">getThis</span><span style="color: #007700">() {<br /> return </span><span style="color: #0000BB">$this</span><span style="color: #007700">;<br /> }<br /><br /> function </span><span style="color: #0000BB">destroyThis</span><span style="color: #007700">() {<br /> </span><span style="color: #0000BB">$baz </span><span style="color: #007700">=& </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">getThis</span><span style="color: #007700">();<br /> }<br />}<br /><br /></span><span style="color: #0000BB">$bar </span><span style="color: #007700">= new </span><span style="color: #0000BB">Foo</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$bar</span><span style="color: #007700">-></span><span style="color: #0000BB">destroyThis</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">$bar</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
</div>
<p class="para">
In PHP 5.0.3, <var class="varname">$bar</var> evaluated to <b><tt class="constant">NULL</tt></b>
instead of returning an object. That happened because
<i>getThis()</i> returns by value, but the value here is
assigned by reference. Although it now works in the expected way, this is
actually invalid code which will throw an <b><tt class="constant">E_NOTICE</tt></b>
under PHP 4.4 or an <b><tt class="constant">E_STRICT</tt></b> under PHP 5.0.4 and up.
</p>
</div>
<div id="migration51.references-works" class="section">
<h2 class="title">Code that failed under PHP 4.3.x, but now works</h2>
<div class="informalexample">
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">function &</span><span style="color: #0000BB">f</span><span style="color: #007700">() {<br /> </span><span style="color: #0000BB">$x </span><span style="color: #007700">= </span><span style="color: #DD0000">"foo"</span><span style="color: #007700">;<br /> </span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">$x</span><span style="color: #007700">);<br /> print </span><span style="color: #DD0000">"</span><span style="color: #0000BB">$x</span><span style="color: #DD0000">\n"</span><span style="color: #007700">;<br /> return(</span><span style="color: #0000BB">$a</span><span style="color: #007700">);<br />}<br /><br />for (</span><span style="color: #0000BB">$i </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">; </span><span style="color: #0000BB">$i </span><span style="color: #007700">< </span><span style="color: #0000BB">3</span><span style="color: #007700">; </span><span style="color: #0000BB">$i</span><span style="color: #007700">++) {<br /> </span><span style="color: #0000BB">$h </span><span style="color: #007700">= &</span><span style="color: #0000BB">f</span><span style="color: #007700">();<br />}<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<p class="para">
In PHP 4.3 the third call to <a href="function.var-dump.php" class="function">var_dump()</a> produces
<b><tt class="constant">NULL</tt></b>, due to the memory corruption caused by
returning an uninitialized value by reference. This is valid code
in PHP 5.0.4 and up, but threw errors in earlier releases of PHP.
</p>
</div>
<div class="informalexample">
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br />$arr </span><span style="color: #007700">= array(</span><span style="color: #DD0000">'a1' </span><span style="color: #007700">=> array(</span><span style="color: #DD0000">'alfa' </span><span style="color: #007700">=> </span><span style="color: #DD0000">'ok'</span><span style="color: #007700">));<br /></span><span style="color: #0000BB">$arr </span><span style="color: #007700">=& </span><span style="color: #0000BB">$arr</span><span style="color: #007700">[</span><span style="color: #DD0000">'a1'</span><span style="color: #007700">];<br />echo </span><span style="color: #DD0000">'-'</span><span style="color: #007700">.</span><span style="color: #0000BB">$arr</span><span style="color: #007700">[</span><span style="color: #DD0000">'alfa'</span><span style="color: #007700">].</span><span style="color: #DD0000">"-\n"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
<p class="para">
Until PHP 5.0.5, it wasn't possible to assign an array element by
reference in this way. It now is.
</p>
</div>
</div>
<div id="migration51.references-didnotwork" class="section">
<h2 class="title">Code that <i>should have worked</i> under PHP 5.0.x</h2>
<p class="para">
There are a couple of instances of bugs reported under PHP 5.0 prior to
the reference fixes which now 'work'. However, in both cases errors are
thrown by PHP 5.1.x, because the code was invalid in the first place.
Returning values by reference using <i>self::</i> now works
in the general case but throws an <b><tt class="constant">E_STRICT</tt></b> warning,
and although your mileage may vary when assigning by reference to an
overloaded object, you will still see an <b><tt class="constant">E_ERROR</tt></b>
when you try it, even where the assignment itself appears to work.
</p>
</div>
<div id="migration51.references-warnings" class="section">
<h2 class="title">Warnings that came and went</h2>
<p class="para">
Nested calls to functions returning by reference are valid code under both
PHP 4.3.x and PHP 5.1.x, but threw an unwarranted
<b><tt class="constant">E_NOTICE</tt></b> or <b><tt class="constant">E_STRICT</tt></b> under the
intervening PHP releases.
</p>
<div class="informalexample">
<div class="example-contents programlisting">
<div class="phpcode"><code><span style="color: #000000">
<span style="color: #0000BB"><?php<br /></span><span style="color: #007700">function & </span><span style="color: #0000BB">foo</span><span style="color: #007700">() {<br /> </span><span style="color: #0000BB">$var </span><span style="color: #007700">= </span><span style="color: #DD0000">'ok'</span><span style="color: #007700">;<br /> return </span><span style="color: #0000BB">$var</span><span style="color: #007700">;<br />}<br /><br />function & </span><span style="color: #0000BB">bar</span><span style="color: #007700">() {<br /> return </span><span style="color: #0000BB">foo</span><span style="color: #007700">();<br />}<br /><br /></span><span style="color: #0000BB">$a </span><span style="color: #007700">=& </span><span style="color: #0000BB">bar</span><span style="color: #007700">();<br />echo </span><span style="color: #DD0000">"</span><span style="color: #0000BB">$a</span><span style="color: #DD0000">\n"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">?></span>
</span>
</code></div>
</div>
</div>
</div>
</div><?php manual_footer(); ?>