2008年8月28日星期四

Re: [fw-core] Deep Cloning Zend_Config

Hi,

Thanks very much for the report! I've resolved this on the trunk in
svn r11113.

Regards,

Rob...


On 26 Aug 2008, at 20:25, Daniel Skinner wrote:

> 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
>
> Kind Regards,
>
> *Daniel Skinner*
> **
> skinner@destiny-denied.co.uk <mailto:skinner@destiny-denied.co.uk>
> www.destiny-denied.co.uk <http://www.destiny-denied.co.uk/>
>

没有评论: