472,968 Members | 1,715 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,968 software developers and data experts.

possible bug with recursive array references

Hello,

I am using PHP 5.0.4 with Apache 2, on WinXP Pro. This behavior
appears to be fundamental however, and should not be affected by
platform.

It would seem that there is some kind of bug in the process that
creates the reference when it is being assigned to an array element
within itself. If it is already referenced, it just assigns the
existing reference and avoids the problem.

As I was reading the documentation about references, I noticed the
warning about "complex arrays". Here is what it says:

----- begin PHP docs -----
Complex arrays are sometimes rather copied than referenced. Thus
following example will not work as expected. Example 21-3. References
with complex arrays

<?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()
?>
----- end PHP docs -----

So I decided to play around with this, and sure enough I got the same
results. But after making a few changes, I discovered that the
behavior is caused by recursively assigning the reference, and not due
to the array structure itself. Consider this example code:

<?php
$top = array( 'X' => 1, 'Y' => 1, 'Z' => 0 );
$top['Y'] = &$top;
$top['X'] = &$top;
$top['Z'] = 4;

echo "X = ", var_dump( $top['X']['Z'] );
echo "Y = ", var_dump( $top['Y']['Z'] );
echo "Z = ", var_dump( $top['Z'] );
?>

The results show:

X = int(0)
Y = int(4)
Z = int(4)

The result for X still has the original value. This would seem to
agree with the orginal statement in the PHP docs. But, if you reverse
the order of the reference assignments like this:

$top['Y'] = &$top;
$top['X'] = &$top;
$top['Z'] = 4;

Then, the result for Y has the original value.

X = int(4)
Y = int(0)
Z = int(4)

Furthermore, if you assign some arbitrary variable a reference to $top
before doing anything else...

$z = &$top;

The output appears to be "correct" now:

X = int(4)
Y = int(4)
Z = int(4)

Looking at the var_dump of the actual resulting array struct reveals
that where the reference is being assigned matches the contents of the
array at *that point in time* up until the next recursive reference
assignment. At that point $top branched off, leaving the first one
pointing to the previous instance. So it would appear that it is
actually a fractal array structure :) Each member that gets another
ref to $top adds another fractal generation to the var_dump.

But nonetheless, assigning a reference to a separate variable stops the
branching for all subsequent recursive reference assignments. So it
appears that assigning a reference to an element within itself like
that does not correctly create the reference, unless the reference was
already created.

Another way to demonstrate this is to compare the output of these two
scripts:

<?php
$top = array( 'W' => 1, 'X' => 1, 'Y' => 1, 'Z' => 0 );
$top['WW'] = 'wwwww'; $top['W'] = &$top; unset ( $top['WW'] );
$top['XX'] = 'xxxxx'; $top['X'] = &$top; unset ( $top['XX'] );
$top['YY'] = 'yyyyy'; $top['Y'] = &$top; unset ( $top['YY'] );
$top['Z'] = 4;
var_dump( $top );
?>

<?php
$top_t = array( 'W' => 1, 'X' => 1, 'Y' => 1, 'Z' => 0 );
$top_t['WW'] = 'wwwww'; $top_w = $top_t; $top_w['W'] = &$top_w; unset (
$top_w['WW'] );
$top_w['XX'] = 'xxxxx'; $top_x = $top_w; $top_x['X'] = &$top_x; unset (
$top_x['XX'] );
$top_x['YY'] = 'yyyyy'; $top_y = $top_x; $top_y['Y'] = &$top_y; unset (
$top_y['YY'] );
var_dump( $top_y );
?>

Basically, the output is the same, except that in the first one, the
dump of $top['Y']['Y'] is shorted to "*RECURSION*" but not in the
second.

Now compare the output of these two scripts:

<?php
for ( $i = 0; $i < 10; $i ++ ) $top[$i] = &$top;
$top['A'] = 'AAAAA'; var_dump( $top );
?>

<?php
$z = &$top;
for ( $i = 0; $i < 10; $i ++ ) $top[$i] = &$top;
$top['A'] = 'AAAAA'; var_dump( $top );
?>

The only difference is the reference assignment at the beginning of the
second one. But the results differ vastly. The first outputs over
157457 lines, while the second only outputs about 2554 lines.

What I would like to know, is if this is actually a bug, or if this
behavior is intentional. I do not have much knowledge of how the Zend
Engine creates the references. But I find it at least somewhat
dangerous that it can have that "fractal" effect so easily. And since
it can be avoided by simply setting a reference to a separate variable,
I am convinced that something is broken (or at least VERY confusing).

The design of the language does not seem to justify this statement:

"make a direct reference assignment to the array before adding
recursive references inside it, or else the structure will branch with
each assignment"

So... any thoughts?

Thanks,
Kaptain524

Jul 17 '05 #1
2 1963
Kaptain524 wrote:
Hello,

I am using PHP 5.0.4 with Apache 2, on WinXP Pro. This behavior
appears to be fundamental however, and should not be affected by
platform.
<snip> What I would like to know, is if this is actually a bug, or if this
behavior is intentional.


If we're voting I say BUG!

Following on from the recent discussion of typing in PHP, I like the way it
uses context to cast type, but I can't see how that could be used as a
basis for justifying this kind of behaviour[1]; it just seems inconsistent.

[1] - not that I am aware of anybody actually doing so

C.

Jul 17 '05 #2
I found another workaround to "correctly" assign the recursive array
references:

<?php
function &foo( &$a ) { return $a; }

$top = array( 'X' => 1, 'Y' => 1, 'Z' => 0 );
$top['Y'] = &foo( $top );
$top['X'] = &foo( $top );
$top['Z'] = &foo( $top );

echo "X = ", var_dump( $top['X']['Z'] );
echo "Y = ", var_dump( $top['Y']['Z'] );
echo "Z = ", var_dump( $top['Z'] );
?>

Apparently, passing by reference into a function and then returning the
reference does not affect the original variable the way it does when
the reference is created directly. I think this certainly makes it
look more like a bug.

Thanks,
Kaptain524

Jul 17 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: peter | last post by:
Hello all, Recently I've started to refactor my code ...(I'm using python 2.3.4) I tried to add extra functionality to old functions non-intrusively. When I used a construct, which involves...
6
by: Johan Bergman | last post by:
Hi, Maybe someone can help me with this one. The following describes a somewhat simplified version of my problem, but I think it will be sufficient. I want to use class factories (virtual...
4
by: darin dimitrov | last post by:
Hello, I need help with an algoritm that given a set of "n" distinct numbers will generate all the possible permutations of fixed length "m" of these numbers WITH repetitions (a total of n^m...
9
by: Csaba Gabor | last post by:
Inside a function, I'd like to know the call stack. By this I mean that I'd like to know the function that called this one, that one's caller and so on. So I thought to do: <script...
6
by: Juha Nieminen | last post by:
Multiple inclusion of the same header file can cause the compilation to fail because of multiple definitions of the same type. That's why it's standard practice to write all headers like this: ...
1
by: rekkufa | last post by:
I am currently building a system for serializing python objects to a readable file-format, as well as creating python objects by parsing the same format. It is more or less complete except for a...
3
dlite922
by: dlite922 | last post by:
I need to get a list of employees out of a database table. I need to end up with an array of ids (primary keys) such as Array(03,9,2,5,1) The employee table has a self reference so that...
4
by: ThEoNeAnDOnLy | last post by:
I recently had an issue with my recursive project in class. Here is the code. // Recursion.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include...
3
by: from.future.import | last post by:
Hi, I encountered garbage collection behaviour that I didn't expect when using a recursive function inside another function: the definition of the inner function seems to contain a circular...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
tracyyun
by: tracyyun | last post by:
Hello everyone, I have a question and would like some advice on network connectivity. I have one computer connected to my router via WiFi, but I have two other computers that I want to be able to...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
3
by: nia12 | last post by:
Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.