php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #17959 array reference problems
Submitted: 2002-06-25 00:41 UTC Modified: 2004-07-26 22:55 UTC
Votes:3
Avg. Score:4.3 ± 0.9
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: pkeshish at yahoo dot com Assigned:
Status: Closed Package: Documentation problem
PHP Version: 4CVS-20021218(STABLE) OS: linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: pkeshish at yahoo dot com
New email:
PHP Version: OS:

 

 [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 =&gt; $v\n" );
  }
?>
</pre>
<pre>
  top['A']:
<?
  foreach ( $top['A'] as $k => $v ) {
    printf( "    $k =&gt; $v\n" );
  }
?>
</pre>
<pre>
  top['B']:
<?
  foreach ( $top['B'] as $k => $v ) {
    printf( "    $k =&gt; $v\n" );
  }
?>
</pre>
<pre>
  top['B']['B_b']:
<?
  foreach ( $top['B']['B_b'] as $k => $v ) {
    printf( "    $k =&gt; $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 =&gt; $v\n" );
  }
?>
</pre>
<pre>
  top['A']:
<?
  foreach ( $top['A'] as $k => $v ) {
    printf( "    $k =&gt; $v\n" );
  }
?>
</pre>
<pre>
  top['B']:
<?
  foreach ( $top['B'] as $k => $v ) {
    printf( "    $k =&gt; $v\n" );
  }
?>
</pre>
<pre>
  top['B']['B_b']:
<?
  foreach ( $top['B']['B_b'] as $k => $v ) {
    printf( "    $k =&gt; $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
?>

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-07-13 18:29 UTC] derick@php.net
Please provide a SHORT reproducing script.

Derick
 [2002-07-16 08:40 UTC] pkeshish at yahoo dot com
<?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-23 16:24 UTC] hholzgra@php.net
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-29 06:50 UTC] pkeshish at yahoo dot com
<?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-11-27 22:57 UTC] mikemc-phpbug at contactdesigns dot com
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 "pkeshish@yahoo.com" 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.
 [2002-12-07 01:46 UTC] iliaa@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php4-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php4-win32-latest.zip

Could you confirm that the problem still exists in latest CVS and if it does ,please provide a SMALL (10 or so) line script that could be used to replicate the problem.
 [2002-12-19 12:12 UTC] pkeshish at yahoo dot com
I grabbed Apache/1.3.27 built and installed it.

Next I grabbed php4-STABLE-200212182230 built and
installed it.

The same test-case presented in this bug report failed.

I also grabbed php4-200212191630 a few minutes ago
built and installed it.

Again, the very same test-case in this bug report failed.

--patrick
 [2002-12-21 11:03 UTC] moriyoshi@php.net
Related to bug #20993(http://bugs.php.net/20993)

 [2002-12-21 15:08 UTC] moriyoshi@php.net
Reclassification & version update
 [2004-07-26 22:55 UTC] vrana@php.net
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()
?>

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 21:01:30 2024 UTC