php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #34069 Named variable array not correctly returned from within member function
Submitted: 2005-08-10 16:07 UTC Modified: 2005-08-11 09:47 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: davydm at gmail dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 4.4.0 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: davydm at gmail dot com
New email:
PHP Version: OS:

 

 [2005-08-10 16:07 UTC] davydm at gmail dot com
Description:
------------
I have a class which maintains heirachical data, as would be (and, indeed, is) represented with xml. The class basically provides a programmable interface to an xml data transport, allowing for data to be transported from php to a tcl middleware server to be parsed and used. So far, so good.

The best way to explain is to demonstrate:
If I were to load an instance of the object with the following xml:
<data>
   <name>Foo</name>
   <descr>Bar</descr>
   <child>
       <name>Childname</name>
       <descr>Childdescr></descr>
   </child>
</data>
I would get an object which has:
$obj->name == "Foo"
$obj->descr == "Bar"
$obj->child[0]->name == "Childname"
$obj->child[0]->descr == "Childdescr"
and so forth. The class allows for nodes with the same name, which are then placed into an an array, hence the array notation on the child node above.

The oddity I have hit upon seems to be a PHP bug, but I'm well open to suggestions. In programming the class, I wanted a consistent interface with the TCL class I have that handles the same functionality, so there are times when I have replicated interface functions even when they are not necessairly required (for the sake of completeness). One such interface mirroring is the get_child function, which takes in the following arguments:
$childname (string)
$idx (integer)
and returns a reference to the child named by the $childname and pointed to by the $idx (if there is one).

The wierdness is that in the original implementation of get_child, where I just checked that the child name was known and the key existed in the array, I did:
return $this->$childname[$idx];
once I had verified with array_key_exists that the element actually existed, I *always* got back null. If I referenced the child from outside of the class (with $obj->childname[$idx]), the child object is quite alright and there, and alive and all of that.
The wierdness steps up a notch when I change the internals of get_child: instead of just returning the object with:
return $this->$childname[$idx];
I do:
foreach ($this->$childname as $cidx => $child) {
    if ($cidx == $idx) {
         return $child;
    }
}
and VOILA!, I get back the child I was looking for. The code is less efficient, of course, because I have to iterate over the child array. But that's not the thing that really bothers me -- I'm more bothered as to *why* this happens, and the only explanation I can see is something lower-level and internal to PHP

Reproduce code:
---------------
Please have a look at http://dascafe.lesbean.net/hdobj.php.gz , starting at line 289, which is the function definition for get_child. You can also see that I've used a foreach in the function toXML(), instead of using the child indeces and the child_count function, as I originally intended. If I can supply more code, please let me know.

Expected result:
----------------
With the commented out code in place, I expect a reference to a member variable of the class which is itself an object of the same class.

Actual result:
--------------
When I use the commented out code, I get a NULL reference instead of the object. Using the foreach to iterate over each element in the $childname array, and returning the child with a matching index works -- although they should have exactly the same result.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-08-10 16:13 UTC] tony2001@php.net
>If I can supply more code, please let me know.
No, thanks.
Could you plz provide a short but complete script max 20 lines long that can be copy/pasted to reproduce the problem?
Thanks.
 [2005-08-10 16:36 UTC] davydm at gmail dot com
I'm afraid that the giant 25 lines below is the smallest I can get a full example of what I'm talking about, since the problem is a little complex.

// begin php code
class Foo {
	function Foo() {
		$this->arrFoo = array("one", "two", "three");
	}
	function getFoo($name, $idx) {
		if (array_key_exists($idx, $this->$name)) {
			return $this->$name[$idx];
		} else {print("no $name here of that $idx");}
	}
	function getBar($name, $idx) {
		if (array_key_exists($idx, $this->$name)) {
			foreach ($this->$name as $fidx => $val) {
				if ($fidx == $idx) return $val;
			}
		} else {print("no $name here of that $idx");}
	}
}
$myfoo = new Foo();
$badret = $myfoo->getFoo("arrFoo", 0); // bad return example
$goodret = $myfoo->getBar("arrFoo", 0); // kludged good return
var_dump($ret);
print("<br>");
var_dump($myfoo->arrFoo[0]); // direct access works ok
print("<br>");
var_dump($goodret);
// end php code
 [2005-08-10 16:46 UTC] tony2001@php.net
And add please expected and actual results of this code.
 [2005-08-10 16:51 UTC] tony2001@php.net
Doesn't matter, I got it.
Use $this->{$name}[$idx] syntax in this case, as the Engine can't guess what are you referring to: 
to $this->{$name[0]} or to $this->{$name}[0].
If you set error_reporting to E_ALL, you'll see appropriate notices.
 [2005-08-11 09:47 UTC] davydm at gmail dot com
The oddity is that the strange behaviour only occurs when referring to the variable from within the class. If i had:

$mvarname = "arrFoo";
$obj = new Foo();

I can get a reference to an array item with:
var_dump($obj->$mvarname);
but not with
var_dump($this->$mvarname);
from within the class (assuming of course, that $mvarname was set within the function attempting to do this in the class).

The behaviour is inconsistent, and not at all what was expected, since the exepected behaviour is shown when accessing the member variable from outside of the class.

The report is most definitely not bogus -- it's an inconsistency in the engine. If you want to leave it as such, that's fine with me -- I just wanted to bring it to your attention, since inconsistent behaviour in a language / engine is normally considered a bug.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri May 03 19:01:32 2024 UTC