ID: 17959
Comment by: [EMAIL PROTECTED]
Reported By: [EMAIL PROTECTED]
Status: Open
Bug Type: Scripting Engine problem
Operating System: linux
PHP Version: 4.2.1
New Comment:
I have experienced similar problems with PHP on Linux 2.4.x. It only
seems to occur in very weird circumstances where you have a reference
pointing (yes I know references are not pointers) to an array element.
My only test cases are much larger that those presented by
"[EMAIL PROTECTED]" as they involve production code. The one piece of
information I can offer which may be of some use is that in my case,
the problem can be eliminated by removing an uneeded "global" statement
(the reference was already in scope). I realize that sounds absurd,
but I have a case where "global" actually breaks the reference. When I
comment out the global statement, the reference doesn't get wiped out.
I know the reference is global because it was created in $GLOBALS. I
know this seems strange, but I can var_dump it before and after and the
only thing that changes is me commenting out the global statement.
Previous Comments:
------------------------------------------------------------------------
[2002-07-29 06:50:20] [EMAIL PROTECTED]
<?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>
------------------------------------------------------------------------
[2002-07-23 16:24:54] [EMAIL PROTECTED]
think of the "global $p;" construct as a shortcut for
"$p = &$GLOBALS['p'];"
so by assigning a new reference you are breaking the one to the global
variable
so you have to explicitly assign to $GLOBALS["p"] here
(marked as documentation problem)
------------------------------------------------------------------------
[2002-07-16 08:40:10] [EMAIL PROTECTED]
<?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>
------------------------------------------------------------------------
[2002-07-13 18:29:59] [EMAIL PROTECTED]
Please provide a SHORT reproducing script.
Derick
------------------------------------------------------------------------
[2002-06-25 00:41:53] [EMAIL PROTECTED]
<?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
?>
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=17959&edit=1