ZF-5771: Wrong pointer position after unsetting data.
Description
require_once 'Zend/Config.php';
$config = new Zend_Config(array(
'first' => array(1),
'second' => array(2),
'third' => array(3)
), true);
foreach ($config as $key => $value)
{
echo $key . PHP_EOL;
if ($key == 'first') {
unset($config->$key); // uses magic Zend_Config::__unset() method
}
}
first
second
third
first
third
Comments
Posted by Rob Allen (rob) on 2009-02-14T05:16:41.000+0000
This is the most simple test code I could come up with to show the problem.
I have no idea how to fix it!
Posted by Rob Allen (rob) on 2009-02-14T06:39:48.000+0000
Corrected file that shows reduced use-case
Posted by Rob Allen (rob) on 2009-02-14T06:45:03.000+0000
Solution to the reduced test case - no optimisation. Created with help from Freeaqingme and Jon Whitcraft on #zftalk.dev.
Obvious optimisation is to store the deleted keys in and _deleted array to save iterating over _data.
Posted by Robin Skoglund (robinsk) on 2009-02-14T09:07:02.000+0000
This patch solves the problem as currently described in the issue, and all Zend/Config* unit tests run fine with this patch.
However, I still think the patch needs more testing before applying it to the trunk.
Posted by Rob Allen (rob) on 2009-02-14T11:12:58.000+0000
Robin,
Your patch fixes the described problem but introduces another one:
The first next() doesn't get called, so the output becomes: second second third
rather than the expected second third
Posted by Jan Pieper (jpieper) on 2009-02-14T14:17:37.000+0000
I think I´ve found a solution.
Posted by Rob Allen (rob) on 2009-02-14T14:47:06.000+0000
Same basic solution, but more comprehensive exercising of the code.
Posted by Rob Allen (rob) on 2009-02-14T14:54:20.000+0000
Updated the reduced testcase file to include the more robust set of exercises. File is reduced_testcase2.php.
Posted by Robin Skoglund (robinsk) on 2009-02-14T15:55:03.000+0000
I attached a file 'robinsk_testcase_and_patch.tar.gz', which includes a modified version of Zend_Config with 6 runnable tests (not unit tests). The patch is also in the archive.
Summary of patch: Set $this->_iterationUnsetFlag = true in the __unset() method. If the flag is true, next() will not advance the internal pointer, but just flip the flag to false. Other iterator methods will also set the flag to false, so the internal state of the pointer/flag is not corrupted. This is way more efficient than maintaining deleted keys or using string operations.
To run tests: * Download robinsk_testcase_and_patch.tar.gz * $ tar -zxvf robinsk_testcase_and_patch.tar.gz * $ php test1.php * $ php test2.php * ... * $ php test6.php
Each test outputs what it tests, and what the expected and actual results are.
Posted by Rob Allen (rob) on 2009-03-14T14:39:21.000+0000
Fixed on trunk - r14321.