History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: ZF-4107
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Rob Allen
Reporter: Matthew Ratzloff
Votes: 1
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Google issue summary
Zend Framework

Zend_Config instances should perform deep copy on clone

Created: 28/Aug/08 08:52 AM   Updated: 29/Aug/08 05:52 AM
Component/s: Zend_Config
Affects Version/s: None
Fix Version/s: 1.6.1

Time Tracking:
Not Specified

Tags:
Participants: Matthew Ratzloff and Rob Allen


 Description  « Hide
From Daniel Skinner
================

I am getting unexpected behaviour when cloning a Zend_Config object:

Example (actual behaviour):

$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = clone $parent;
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'  - as expected
echo $parent->key->nested; // 'override' - I was expecting this to be 'parent'

Intuitive behaviour (what makes sense):

Cloning a Zend_Config object should completely separate the new instance from the original - i.e. there should be no cross-references.

$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = clone $parent;
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'
echo $parent->key->nested; // 'parent'

This is occurring because cloning Zend_Config only creates a shallow clone currently.

Solution 1: Cast to an array and create a new instance:

This can be achieved already and effectively creates a deep clone.

$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = new Zend_Config($parent->toArray(), true); //cast the parent object to an array and create a new Zend_Config
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'  - as expected
echo $parent->key->nested; // 'parent' - as expected

Solution 2: Fixing Zend_Config to perform a deep clone:

/**
   * Perform a deep clone of this instance to allow side-effect free cloning.
   * @return void
   */
  public function __clone()
  {
      $data = array();
      foreach ($this->_data as $key => $value)
      {
          if ($value instanceof Zend_Config)
          {
              $data[$key] = clone $value;
          } else {
              $data[$key] = $value;
          }
      }
      $this->_data = $data;
  }

Gives:

$parent = new Zend_Config(array('key' => array('nested' => 'parent')), true); //allow read-write for merging
$newConfig = clone $parent;
$newConfig->merge(new Zend_Config(array('key' => array('nested' => 'override')), true));
echo $newConfig->key->nested; // 'override'  - as expected
echo $parent->key->nested; // 'parent' - as expected

It makes sense to me that this is the expected behaviour when cloning and a deep clone greatly reduces the chance of hard to detect side-effects. Does anybody disagree?

A full description of the above can be found at: http://www.daniel-skinner.co.uk/cloning-zend_config-without-side-effects/26/08/2008

Test cases and a patch can be found at: http://www.destiny-denied.co.uk/files/ZendConfigClone.zip



 All   Comments   Work Log   Change History   FishEye   Crucible      Sort Order: Ascending order - Click to sort in descending order
Rob Allen - 28/Aug/08 01:44 PM
Thanks Daniel for doing the research!

Resolved on trunk in svn r11113.


Rob Allen - 29/Aug/08 05:52 AM
Committed to release-1.6 branch, svn r11119.