Bug #51284 [Bgs]: foreach distroys objects in array

From: Date: Thu, 20 May 2010 08:40:32 +0000
Subject: Bug #51284 [Bgs]: foreach distroys objects in array
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-150645@lists.php.net to get a copy of this message
Edit report at http://bugs.php.net/bug.php?id=51284&edit=1

 ID:               51284
 User updated by:  gerhard at tinned-software dot net
 Reported by:      gerhard at tinned-software dot net
 Summary:          foreach distroys objects in array
 Status:           Bogus
 Type:             Bug
 Package:          Class/Object related
 Operating System: MacOSX, Linux, ...
 PHP Version:      Irrelevant

 New Comment:

Thanks, that solved it. Thanks for that.

Its now the second time i commit a bug to php and as the first time it
was 
immediately closed as Bogus without having a closer look to it. I don't
know 
how much bug reports you have to review every day, but i hope you will
have at 
least a closer look next time i report a bug.


Previous Comments:
------------------------------------------------------------------------
[2010-05-20 10:20:47] gerhard at tinned-software dot net

So my assumption seems to be correct that it has to do with the foreach
loop. 

I will follow your suggestion and try the loop with a & for the second
parameter. 

But in general, ... Wouldn't it be an idea to maybe place a line in the
documentation for that?

------------------------------------------------------------------------
[2010-05-20 08:17:18] mike@php.net

That's true, sorry. You lose the reference because of foreach; try:

foreach ($parameter as $key => &$param) ...

------------------------------------------------------------------------
[2010-05-19 17:45:19] gerhard at tinned-software dot net

This comment is simply not true!!!

How can it be that the function call func_get_args() destroys the
reference when one of this functions work and the other function does
not work? Both functions use this functionb call. But only in the
function get_object_NOK() the error message is shown. In the other
function, the object is created as expected. 

So please explain me how the function call func_get_args() can cause
this?

------------------------------------------------------------------------
[2010-05-19 15:23:49] mike@php.net

I get a Warning: Parameter 2 to test_obj2::__construct() expected to be
a reference, value given in /tmp/phpbugs/51284.php on line 128

You lose the ref with func_get_args().

------------------------------------------------------------------------
[2010-03-12 13:29:44] gerhard at tinned-software dot net

Description:
------------
I have a script which tries to create configured objects of classes. The

method creating the object of the named class will generate a unique 
identifier to be able to identify the invocation later in the class.
This 
unique_id is basically calculated by adding the class name and all 
constructor parameters into a ":"-seperetaed list. For doing this i used


This all functions well as long as there is not the following very
special 
combination of parameters and class-parameterlist. If one of the
parameters 
is an object, and this object is passed to the class as reference
(&$object).

In such a case, the foreach loop destroys somehow the $parameter array.
As 
the $parameter array is not altered in the loop, there is no explanation
to 
my way the loop influence the array. 

To prove that the loop is causing this problem i changed the loop from 
foreach() to for(). As you can see in the test script there are 2
methods in 
the OM class. The get_object_OK() uses the for()-loop to generate the ID
and
the get_object_NOK() method uses the foreach()-loop to generate it.

With the for()-loop the script runs without any troubles. But with the 
foreach()-loop the script returns an error while invocating the object.
This 
error causes the object to be not created.

The error message which can be found in the webserver's / php's logfile
is 
the following:
[error] [client 127.0.0.1] PHP Warning:  Invocation of test_obj2's
constructor failed in /.../test.php on line 183, referer:
http://127.0.0.1:8080/
... The line references to "$obj =
$reflection_obj->newInstanceArgs($parameter);" at the get_object_NOK.()
function.


Test script:
---------------
class test_obj
{
    var $test = "abc";
    
    function __construct($str)
    {
        $this->test = $str;
    }
    
    function get()
    { 
        echo get_class($this)." - string=".$this->test."<br />\n";
    }
    
    function set($str)
    {
        $test = $str;
    }
}

class test_obj2
{
    var $test = "abc";
    
    function __construct($string1, &$object)
    {
        echo get_class($this)." - string1=$string1<br />\n";
        $object->get();
    }
}





//include_once(dirname(__FILE__).'/object_manager.class.php');
//include_once(dirname(__FILE__).'/element_container.class.php');


//
// Test execution
//
echo "PHP Version: ".phpversion()."<br /><br />\n";
$om = new OM();

$t1 = new test_obj("init-text-object-1");
$t1->get();
echo "Object of class 'Test_CLass' ... Finished.<br />\n";


$t2 = $om->get_object_OK("test_obj2", "object-text-2", $t1);
echo "Object of class 'Test_CLass2' with for() loop ... Finished.<br
/>\n";

$t2 = $om->get_object_NOK("test_obj2", "object-text-2", $t1);
echo "Object of class 'Test_CLass2' with foreach() loop ... Finished.<br
/>\n";




//
// A short testing code from a much biger function / Class to 
// demonstrate the behaviour
//
class OM
{
    function get_object_OK()
    {
        $parameter = func_get_args();
        $type = array_shift($parameter);
        
        //
        // create unique identifier for this object creation.
        // Used in the original class to identify the object later in
the class.
        //
        $unique_id = "$type:";
        // loop through all parameters
        for($i=0; $i < count($parameter); $i++)
        {
            // if parameter is an object, get only the object name
            if(is_object($parameter[$i]) === TRUE)
            {
                $unique_id .= get_class($parameter[$i]).':';
                continue;
            }
            // get the variable content as string to the
identifier-string
            $unique_id .= gettype($parameter[$i]).':';
        }
        
        //
        // Creating the object by name
        //
        $reflection_obj = new ReflectionClass($type);      
        $obj = $reflection_obj->newInstanceArgs($parameter); 
        
        // return the created object
        return $obj;
    }
    
    function get_object_NOK()
    {
        $parameter = func_get_args();
        $type = array_shift($parameter);
        
        //
        // create unique identifier for this object creation.
        // Used in the original class to identify the object later in
the class.
        //
        $unique_id = "$type:";
        // loop through all parameters
        foreach($parameter as $key => $param)
        {
            // if parameter is an object, get only the object name
            if(is_object($param) === TRUE)
            {
                $unique_id .= get_class($param).':';
                continue;
            }
            // get the variable content as string to the
identifier-string
            $unique_id .= gettype($param).':';
        }
        
        //
        // Creating the object by name
        //
        $reflection_obj = new ReflectionClass($type);      
        $obj = $reflection_obj->newInstanceArgs($parameter); 
        
        // return the created object
        return $obj;
    }
}


Expected result:
----------------
The script should successfully create an object when for() or
foreach()-loop 
is used.


Actual result:
--------------
The script works only with for()-loop. When the foreach look is used,
the 
following error message is shown.
[error] [client 127.0.0.1] PHP Warning:  Invocation of test_obj2's
constructor failed in /.../test.php on line 183, referer:
http://127.0.0.1:8080/
... The line references to "$obj =
$reflection_obj->newInstanceArgs($parameter);" at the get_object_NOK.()
function.



------------------------------------------------------------------------



-- 
Edit this bug report at http://bugs.php.net/bug.php?id=51284&edit=1


Thread (7 messages)

« previous php.bugs (#150645) next »