php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #51284 foreach distroys objects in array
Submitted: 2010-03-12 13:29 UTC Modified: 2010-05-20 10:40 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: gerhard at tinned-software dot net Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: Irrelevant OS: MacOSX, Linux, ...
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: gerhard at tinned-software dot net
New email:
PHP Version: OS:

 

 [2010-03-12 13:29 UTC] 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.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-05-19 15:23 UTC] mike@php.net
-Status: Open +Status: Bogus
 [2010-05-19 15:23 UTC] 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-05-19 17:45 UTC] 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-20 08:17 UTC] mike@php.net
That's true, sorry. You lose the reference because of foreach; try:

foreach ($parameter as $key => &$param) ...
 [2010-05-20 10:20 UTC] 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 10:40 UTC] gerhard at tinned-software dot net
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.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 18:01:31 2024 UTC