|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2002-06-25 00:41 UTC] pkeshish at yahoo dot com
<?php
//
// There seems to be some issues with how array references
// are handled by PHP, unless, my understanding of how
// array()s and references to them are supposed to work is
// seriously flawed.
//
// Unfortunately i don't have enough time on my hands to
// dig through PHP sources.
//
// The source below seems to be a few very simple test-cases
// pointing out the bug that's caused me enough grief.
// Hopefully, someone can use this information in tracking
// down the bug and eventually fixing it.
//
// The following issues can be duplicated on both
// PHP Versions 4.1.2 and 4.2.1
//
// I'm not much concerned about 'Case 1' as I am about
// cases 3 and 4. They seem more serious problems.
//
?>
<? // -- Case 1
// This case demonstrates that $top['B']['B_b']['parent'] loses
// the reference to parent array!
//
$top =
array
(
'name' => 'top',
'parent' => null,
'A' =>
array
(
'name' => 'A',
'parent' => &$top,
),
'B' =>
array
(
'name' => 'B',
'parent' => &$top,
'B_b' =>
array
(
'name' => 'B_b',
'parent' => &$top['B'],
),
),
);
?>
<pre>
case 1:
top:
<?
foreach ( $top as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<pre>
top['A']:
<?
foreach ( $top['A'] as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<pre>
top['B']:
<?
foreach ( $top['B'] as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<pre>
top['B']['B_b']:
<?
foreach ( $top['B']['B_b'] as $k => $v ) {
printf( " $k => $v\n" );
}
//
// What happened to $top['B']['B_b']['parent'] reference?
//
?>
</pre>
<hr align="left" size="5" width="80%">
<? // -- Case 2
// This case shows a work around to above bug.
//
$top =
array
(
'name' => 'top',
//'parent' => null,
'A' =>
array
(
'name' => 'A',
//'parent' => &$top,
),
'B' =>
array
(
'name' => 'B',
//'parent' => &$top,
'B_b' =>
array
(
'name' => 'B_b',
//'parent' => &$top['B'],
),
),
);
$top['parent'] = null;
$top['A']['parent'] = &$top;
$top['B']['parent'] = &$top;
$top['B']['B_b']['parent'] = &$top['B'];
?>
<pre>
case 2:
top:
<?
foreach ( $top as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<pre>
top['A']:
<?
foreach ( $top['A'] as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<pre>
top['B']:
<?
foreach ( $top['B'] as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<pre>
top['B']['B_b']:
<?
foreach ( $top['B']['B_b'] as $k => $v ) {
printf( " $k => $v\n" );
}
?>
</pre>
<hr align="left" size="5" width="80%">
<pre>
case 3:
<? // -- Case 3
// This case demonstrates how change_ptr() function fails to actually
// change the value of a global variable $ptr.
//
// Essentially 'global $ptr' seems to only be local to the function
// scope and modifying its value seems to have no bearing on the
// global variable $ptr that we are interested in!!
//
// Please note that the demonstrated behavior is inconsistant with
// how $iref is treated.
//
$ptr = &$top;
$i = 0;
$iref = &$i;
function change_ptr( $name )
{
global $ptr;
global $iref;
$iref++;
printf( " change_ptr($name) " );
if ( $ptr[$name] ) {
$before_change =
sprintf( "before: \$ptr['name'] = %s", $ptr['name'] ) . "\n " .
sprintf( " \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] );
$ptr = &$ptr[$name];
$after_change =
sprintf( "after: \$ptr['name'] = %s", $ptr['name'] ) . "\n " .
sprintf( " \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] );
printf( "<font color=\"green\">CHANGED</font>:\n" );
printf( " %s\n %s", $before_change, $after_change );
}
else
printf( "<font color=\"red\">NO CHANGE!</font>" );
printf( "\n \$iref: $iref<br>\n" );
}
change_ptr('B');
change_ptr('B'); // what is going on?? Why didn't previous call stick?
?>
</pre>
<hr align="left" size="5" width="80%">
<pre>
case 4:
<? // -- Case 4
// This case shows the expected behavior of 'Case 3'.
//
function change_ptr2( $name )
{
global $iref;
$iref++;
printf( " change_ptr2($name) " );
if ( $GLOBALS['ptr'][$name] ) {
$before_change =
sprintf( "before: \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] );
$GLOBALS['ptr'] = &$GLOBALS['ptr'][$name];
$after_change =
sprintf( "after: \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] );
printf( "<font color=\"green\">CHANGED</font>:\n" );
printf( " %s\n %s", $before_change, $after_change );
}
else
printf( "<font color=\"red\">NO CHANGE!</font>" );
printf( "\n \$iref: $iref<br>\n" );
}
change_ptr2('B');
change_ptr2('B'); // good! no change
change_ptr2('B_b');
change_ptr2('parent'); // Back to $top['B']
change_ptr2('parent'); // Back to $top
change_ptr2('A'); // This call will cause a problem soon!
change_ptr2('parent');
change_ptr2('B');
change_ptr2('B_b');
// And just as we were doing so well ...
change_ptr2('parent'); // Grrr! What happened!?!?
// apparently the call change_ptr2('A') screws something up.
?>
</pre>
<?
// ex: ai et sw=2 ts=2
?>
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Nov 13 07:00:02 2025 UTC |
<?php // Here is a slightly modified version of the original // post (case 3). I hope the lenght of this test-case // acceptable as i do not know of a shorter example. // // Thanks, // --patrick // define array we plan to navigate. $top = array ( 'name' => 'top', 'A' => array ( 'name' => 'A', ), 'B' => array ( 'name' => 'B', 'B_b' => array ( 'name' => 'B_b', ), ), ); // setup "parent references" for each of the nodes. $top['parent'] = null; $top['A']['parent'] = &$top; $top['B']['parent'] = &$top; $top['B']['B_b']['parent'] = &$top['B']; // setup our reference to $top. $ptr is what should change // on every call to change_ptr(name). $ptr = &$top; // $i and $iref are meant to demonstrate the inconsistency // of manipulating references w/in functions. $i = 0; $iref = &$i; // change_ptr( name ) does the following w/some verbose // messages to display the state of variables in question. // // if ( ptr[name] ) // ptr = ptr[name]; // function change_ptr( $name ) { // This case demonstrates how change_ptr() function fails // to actually change the value of a global variable $ptr. // // Essentially 'global $ptr' seems to only be local to the // function scope and modifying its value seems to have no // bearing on the global var $ptr that is of interest. // // Please note that the demonstrated behavior is not // inconsistent with how $iref is treated. global $ptr; global $iref; $iref++; printf( " change_ptr($name) " ); if ( $ptr[$name] ) { // Setting up string for later printing. $before_change = sprintf( "before: \$ptr['name'] = %s", $ptr['name'] ) . "\n " . sprintf( " \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] ); $ptr = &$ptr[$name]; $after_change = sprintf( "after: \$ptr['name'] = %s", $ptr['name'] ) . "\n " . sprintf( " \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] ); printf( "<font color=\"green\">CHANGED</font>:\n" ); printf( " %s\n %s", $before_change, $after_change ); } else printf( "<font color=\"red\">NO CHANGE!</font>" ); printf( "\n \$iref: $iref" ); printf( "\n \$GLOBALS['iref']: $iref<br>\n" ); } ?> <pre> <? // The first call to change_ptr('B') is expected to change // globally defined $ptr to become $ptr['B'], hence, the // 2nd call to the change_ptr('B') should fail since // $top['B']['B'] does not exist. change_ptr('B'); change_ptr('B'); // What is going on?? // Why didn't previous call stick? ?> </pre><?php // Dear Php developer, // // After considering your explanation of what exactly 'global $ptr' // is i changed my code to strictly use $GLOBALS['ptr']. However, // after doing so my program still didn't function properly! // // I had to work a bit harder to come up with a simplified example // for you. I believe i have done so below. // // Please pay close attention to the notes w/in comments explaining // strange conditions that would make this sample code to work as // expected. Now I'm certain there EXISTS a serious problem with // the Php engine when processing this code. // // Thanks, // --patrick // define array we plan to navigate. $top = array ( 'name' => 'top', 'A' => array ( 'name' => 'A', 'A_a' => array ( 'name' => 'A_a', 'fn_1' => 'Aa_fn_1', 'fn_2' => 'Aa_fn_2', 'fn_3' => 'Aa_fn_3', 'A_a_1' => array ( 'name' => 'A_a_1', 'fn_1' => 'Aa1_fn_1', 'fn_2' => 'Aa1_fn_2', ), 'A_a_2' => array ( 'name' => 'A_a_2', 'fn_1' => 'Aa2_fn_1', 'fn_2' => 'Aa2_fn_2', ), ), ), ); // setup "parent references" for each of the nodes. $top['parent'] = null; $top['A']['parent'] = &$top; $top['A']['A_a']['parent'] = &$top['A']; $top['A']['A_a']['A_a_1']['parent'] = &$top['A']['A_a']; $top['A']['A_a']['A_a_2']['parent'] = &$top['A']['A_a']; //$top['A']['A_a']['A_a_1']['parent'] = &$top['A']['A_a']; // // Note! // Here if we uncomment the above line the sample code will // magically WORK! // // Why does the order of initialization matter!? And will the // code now break elsewhere? // setup our reference to $top. $ptr is what should change // on every call to change_ptr(name). $ptr = &$top; // change_ptr( name ) does the following w/some verbose // messages to display the state of variables in question. // // if ( ptr[name] ) // ptr = ptr[name]; // function change_ptr( $name ) { printf( " change_ptr($name) " ); if ( $GLOBALS['ptr'][$name] ) { // Setting up string for later printing. $before_change = sprintf( "before: \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] ); $GLOBALS['ptr'] = &$GLOBALS['ptr'][$name]; $after_change = sprintf( "after: \$GLOBALS['ptr']['name'] = %s", $GLOBALS['ptr']['name'] ); printf( "<font color=\"green\"><b>CHANGED</b></font>:\n" ); printf( " %s\n %s", $before_change, $after_change ); } else printf( "<font color=\"red\"><b>NO CHANGE!</b></font>" ); printf( "<br>\n" ); } ?> <pre> <? // All of the following calls should succeed and print // 'CHANGED'. However, you will notice that the last call // will fail to change $ptr to point to the 'parent' of // $top['A']['A_a']['A_a_2']. // change_ptr('A'); change_ptr('A_a'); change_ptr('A_a_1'); change_ptr('parent'); change_ptr('A_a_2'); change_ptr('parent'); ?> </pre>This bug has been fixed in the documentation's XML sources. Since the online and downloadable versions of the documentation need some time to get updated, we would like to ask you to be a bit patient. Thank you for the report, and for helping us make our documentation better. It really doesn't work as expected. Documented with this example: <?php $top = array( 'A' => array(), 'B' => array( 'B_b' => array(), ), ); $top['A']['parent'] = &$top; $top['B']['parent'] = &$top; $top['B']['B_b']['data'] = 'test'; print_r($top['A']['parent']['B']['B_b']); // array() ?>