php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #33977 Only variable references should be returned by reference is buggy
Submitted: 2005-08-03 14:24 UTC Modified: 2005-08-03 20:12 UTC
From: kulakov74 at yandex dot ru Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 4.4.0 OS: Linux
Private report: No CVE-ID: None
 [2005-08-03 14:24 UTC] kulakov74 at yandex dot ru
Description:
------------
Our hosting has upgraded to 4.4.0 and we got the famous notice on returning variable reference. But after fixing my code to comply weith the notice I found it is still displayed at certain circumstances. Unfortunately, I could not isolate the code that behaves this way because of the scripts complexity so I cannot provide a simple code that reproduces it. While trying to figure out what was the reason I found that many minor changes, apparently absolutely not relating to the problem, could prevent the notice from beaing displayed, while otherwise it is displayed. It could be simple output directly before or even anywhere in the script, changing the value of the dummy variable that is returned instead of false, for ex.

$oNewNode=null;
//...
return $oNewNode;

produced the notice while 

$oNewNode=0;

with the same code did not. Logging to a file, changing the line at which the dummy assignment is done and a lot of other changes randomly toggle the irrelevant notice off. I have a script that generates pages html and the same code works with some pages but displays the notice with others; then changing it results in the contrary thing. Finally, I found one bug-proof solution that worked everywhere: 

$oNewNode=&$oNewNode;	return $oNewNode;

but overall working around the problem in the 4.4.0 release has left a very unpleasant feeling of a buggy system. 

Reproduce code:
---------------
This does not reproduce the problem - it's just the piece of code I worked with and I added all the lines I tried to prevent the notice. 

function &add($mixKey, $mixVal=array()){
//Add: either a pair $mixKey=>$mixVal,
//or a node $mixKey with values $mixVal, or an array of pairs $mixKey

//WORKED BUT NOT ALWAYS
$oNewNode=null; $oNewNode=false;
//WORKED ALMOST ALWAYS
$oNewNode=0; $oNewNode=1; 

//array
if (is_array($mixKey)){
	foreach($mixKey as $n => $v) $this->add($n, $v);
	//WORKED NOT ALWAYS
	$oNewNode=0;
	}
//string or a simple array
else if (!is_array($mixVal) || key($mixVal)===0){
	$this->hashValues[$mixKey]=$mixVal;
	//WORKED NOT ALWAYS
	$oNewNode=0;
	}
//node
else{
	$oNewNode=&new Node($mixVal, $this->bCleanup);
	if (!@$this->aNodeGroups[$mixKey]){
		$this->aNodeGroups[$mixKey]=array();
		}
	$this->aNodeGroups[$mixKey][]=&$oNewNode;
	//THIS FOR A REASON RESULTED IN EVEN MORE NOTICES UNLIKE THE COMMON RETURN!
	return $oNewNode;
	}

//NO EFFECT FOR A REASON
if (!isset($oNewNode)) $oNewNode=0;

//THE SOLUTION
$oNewNode=&$oNewNode;

return $oNewNode;
}

Expected result:
----------------
No notices

Actual result:
--------------
A few notices for some pages, none for others

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-08-03 14:35 UTC] derick@php.net
Thank you for this bug report. To properly diagnose the problem, we
need a short but complete example script to be able to reproduce
this bug ourselves. 

A proper reproducing script starts with <?php and ends with ?>,
is max. 10-20 lines long and does not require any external 
resources such as databases, etc.

If possible, make the script source available online and provide
an URL to it here. Try to avoid embedding huge scripts into the report.
 [2005-08-03 17:14 UTC] kulakov74 at yandex dot ru
In order to get the small code, I began deleting and commenting out parts of the scripts watching for the notice to remain. But at some point I found that deleting, commenting out a line or any other changes made the notice disappear. That is the buggy behaviour, I have no idea why this is so. In order to make the code simple, I made larger parts of it not executable with if (0) etc, so that you do not have to understand them even though they are there. The parts are marked as "not working". The point is if I physically remove them and the script is smaller (or even if I double a line) the notice is not displayed, so maybe the size matters. I provide the final code that does display the notice though it should not, and the script is also available at http://hotelsys.biz/dev_ref.php (the result) and at http://hotelsys.biz/dev_ref.php?src=1 (the source code). 

The notice is about return $oNewNode; in function &add(). In the function, I create $oNewNode=false; to prevent the notice, the 2nd branch is executed, and then the return goes. Before calling add(), render() is called. It does almost nothing to the object but is necessary for the notice to appear.

The code follows

<?

if (isset($_GET["src"])){
	highlight_file("dev_ref.php");
	exit;
	}

error_reporting(E_ALL);

$TextNode=new Node();
$TextNode->render();
$TextNode->add('H', 123);

//------------------------------------------------------------------------

class Node{
	var $hashValues;		//any values
	var $aNodeGroups;		//
	var $sTemplate;			//
	var $bDisplay=true;	//don't hide
	var $bCleanup=true;	//autodelete subnodes when used
	//------------------------------------------------------------------------
	
	function Node($hashValues=false, $bCleanup=true){
	$this->hashValues=array();
	}

	function &add($mixKey, $mixVal=array()){
	$oNewNode=false;
	if (is_array($mixKey)){
		if (0){
			//not working!!!
			foreach($mixKey as $n => $v) $this->add($n, $v);
			}
		}
	else if (!is_array($mixVal) || key($mixVal)===0){
		$this->hashValues[$mixKey]=$mixVal;
		}
	else{
		if (0){
			//not working!!!
			$oNewNode=&new Node($mixVal, $this->bCleanup);
			if (!@$this->aNodeGroups[$mixKey]){
				$this->aNodeGroups[$mixKey]=array();
				}
			$this->aNodeGroups[$mixKey][]=&$oNewNode;
			//--not working!!!
			}
		}
	return $oNewNode;
	}

	function render(){
	
 	if (!$this->bDisplay) return "";
	if ($this->aNodeGroups){
		if (0){
			//not working!!!
			foreach($this->aNodeGroups as $GrpName => $aNodes){
				$bDebug=($GrpName=='Content');
				$this->_EndPos=0;	$sAccumulator=false;
				while(is_string($sTemplate=$this->getGrpTemplate($GrpName))){
					if ($sAccumulator===false){
						$sAccumulator=''; $NodeNum=count($aNodes);
						for($i=0; $i<$NodeNum; $i++){
							if ($sTemplate) $aNodes[$i]->sTemplate=$sTemplate;
							$sAccumulator.=$aNodes[$i]->render();
							if ($this->bCleanup) $aNodes[$i]=false;
							else $aNodes[$i]->sTemplate='';
							}
						}
					$this->putLastGrpText($sAccumulator);
					}
			 	}
			
			if ($this->bCleanup) $this->aNodeGroups=false;
			//--not working!!!
			}
		}

	$Templ=$this->sTemplate;
	
	foreach($this->hashValues as $sKey => $mixVal){
		continue;
		//not working!!!
		$sToken='{{'.$sKey.'}}';
		if (!is_array($mixVal)){
			$Templ=str_replace($sToken, $mixVal, $Templ);
			}
		else{
			$Len=count($mixVal); $sAccumulator='';
			for($ValNo=0; $ValNo<$Len; $ValNo++){
				$sAccumulator.=str_replace($sToken, $mixVal[$ValNo], $Templ);
				}
			$Templ=$sAccumulator;
			}
		//---not working!!!
		}

	if ($this->bCleanup) $this->hashValues=array();

	return $Templ;
	}
}

?>
 [2005-08-03 17:26 UTC] tony2001@php.net
Please try using this CVS snapshot:

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

Can't reproduce. This code doesn't produce any warning/notices for me neither with 5.x, nor with 4.4.
 [2005-08-03 18:40 UTC] kulakov74 at yandex dot ru
Afraid I won't be able to test with the latest release
 [2005-08-03 20:12 UTC] tony2001@php.net
We cannot fix something that we can't replicate.
Feel free to repoen the report when you're able to provide a short reproduce case that doesn't work as expected with the latest CVS.
 
PHP Copyright © 2001-2026 The PHP Group
All rights reserved.
Last updated: Wed Mar 25 04:00:01 2026 UTC