php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #49269 Ternary operator fails on Iterator object when used inside foreach declaration
Submitted: 2009-08-16 01:20 UTC Modified: 2009-08-17 07:48 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: president at basnetworks dot net Assigned: colder
Status: Closed Package: Class/Object related
PHP Version: 5.3.0 OS: All
Private report: No CVE-ID:
 [2009-08-16 01:20 UTC] president at basnetworks dot net
Description:
------------
The function isset() produces an incorrect result when used on an object that implements the Iterator interface, within a foreach declaration.

As illustrated below, when used outside of the foreach() declaration, isset() works as expected in the object that implements Iterator interface, returning true, causing the output 'true'.

When isset() is used within the foreach() declaration on the same object, it instead returns false, causing an empty array to be used for the foreach() loop.

There is no reason the isset() function should return anything different when used within the foreach() declaration block.

Reproduce code:
---------------
class NormalClass
{
	public $a, $b, $c;

	public function __construct()
	{
		$this->a = 'a';
		$this->b = 'b';
		$this->c = 'c';
	}
}

class ArrayClass implements Iterator
{
	private $internal_array;

	public function __construct()
	{
		$this->internal_array = array('a', 'b', 'c');
	}

	public function key()
	{
		return key($this->nodes);
	}

	public function current()
	{
		return current($this->nodes);
	}

	public function next()
	{
		next($this->nodes);
	}

	public function valid()
	{
		return (current($this->nodes) !== false) ? true : false;
	}

	public function rewind()
	{
		reset($this->nodes);
	}
}

$array = array('a', 'b', 'c');
$normal_object = new NormalClass();
$array_object = new ArrayClass();

echo "Array: " . (isset($array) ? 'true' : 'false');
echo "\nNormal Object: " . (isset($normal_object) ? 'true' : 'false');
echo "\nArray Object: " . (isset($array_object) ? 'true' : 'false');

echo "\nArray: ";
foreach ((isset($array) ? $array : array()) as $item)
{
	echo $item;
}

echo "\nNormal Object: ";
foreach ((isset($normal_object) ? $normal_object : array()) as $item)
{
	echo $item;
}

echo "\nArray Object: ";
foreach ((isset($array_object) ? $array_object : array()) as $item)
{
	echo $item;
}

Expected result:
----------------
Array: true
Normal Object: true
Array Object: true
Array: abc
Normal Object: abc
Array Object: abc

Actual result:
--------------
Array: true
Normal Object: true
Array Object: true
Array: abc
Normal Object: abc
Array Object: 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-08-16 01:28 UTC] president at basnetworks dot net
I addition to the reproduce code, the following may help to understand the bug:

foreach ($array_object as $item)
{
	echo $item;
}

Will successfully print "abc", while:

foreach ((isset($array_object) ? $array_object : array()) as $item)
{
	echo $item;
}

will not print anything, indicating that isset() is returning false.  I hope that helps.
 [2009-08-16 01:36 UTC] president at basnetworks dot net
After further testing, I have found this bug is stranger than it seems:

foreach ((isset($array_object) ? $array_object : array('1', '2', '3')) as $item)
{
	echo $item;
}

Should either print 'abc' or '123' no matter if isset() is successful or fails.  It prints neither.  Now I am wondering if it is not isset(), but the ternary operator that is failing.
 [2009-08-16 10:52 UTC] sjoerd-php at linuxonly dot nl
Thank you for your bug report.

I could reproduce the behavior and made a code sample to reproduce it:

<?php
class TestObject implements Iterator
{
	private $first = true;
	function valid()
	{
		if ($this->first)
		{
			$this->first = false;
			return true;
		}
		return false;
	}
	function current() { }
	function next() { }
	function key() { }
	function rewind() { }
}

$array_object = new TestObject();

// Without ternary operator, the foreach is entered
foreach ($array_object as $item)
{
	echo "This works.\n";
}

// With ternary operator, the foreach is not entered
foreach ((true ? $array_object : $array_object) as $item)
{
	die("Good. Expected behavior.\n");
}
die("Bad. Foreach was skipped.\n");
?>
 [2009-08-16 10:53 UTC] sjoerd-php at linuxonly dot nl
Thank you for your bug report.

I could reproduce the behavior and made a code sample to reproduce it:

<?php
class TestObject implements Iterator
{
	private $first = true;
	function valid()
	{
		if ($this->first)
		{
			$this->first = false;
			return true;
		}
		return false;
	}
	function current() { }
	function next() { }
	function key() { }
	function rewind() { }
}

$array_object = new TestObject();

// Without ternary operator, the foreach is entered
foreach ($array_object as $item)
{
	echo "This works.\n";
}

// With ternary operator, the foreach is not entered
foreach ((true ? $array_object : $array_object) as $item)
{
	die("Good. Expected behavior.\n");
}
die("Bad. Foreach was skipped.\n");
?>
 [2009-08-16 10:57 UTC] sjoerd-php at linuxonly dot nl
Note that the Iterator in my previous comment sucks and should not be used.
 [2009-08-16 17:21 UTC] president at basnetworks dot net
sjoerd-php at linuxonly dot nl,

Your code sample is much clearer, and seems to narrow it down to the ternary operator mis-behaving.  Thanks for the added clarification, I will update the report.

You should also "vote" that you reproduced the bug above.
 [2009-08-17 00:49 UTC] colder@php.net
http://patches.colder.ch/Zend/bug49269.patch?markup

This should fix it, and passes all the Zend tests, but as it may affect some untested edge cases out there, further checking is required.
 [2009-08-17 07:40 UTC] svn@php.net
Automatic comment from SVN on behalf of dmitry
Revision: http://svn.php.net/viewvc/?view=revision&revision=287396
Log: Fixed bug #49269 (Ternary operator fails on Iterator object when used inside foreach declaration). (Etienne, Dmitry)
 [2009-08-17 07:40 UTC] svn@php.net
Automatic comment from SVN on behalf of dmitry
Revision: http://svn.php.net/viewvc/?view=revision&revision=287397
Log: Fixed bug #49269 (Ternary operator fails on Iterator object when used inside foreach declaration). (Etienne, Dmitry)
 [2009-08-17 07:41 UTC] svn@php.net
Automatic comment from SVN on behalf of dmitry
Revision: http://svn.php.net/viewvc/?view=revision&revision=287398
Log: Fixed bug #49269 (Ternary operator fails on Iterator object when used inside foreach declaration). (Etienne, Dmitry)
 [2009-08-17 07:48 UTC] colder@php.net
This bug has been fixed in SVN.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 18:01:58 2014 UTC