Issues

ZF-5071: Deep clone support please.

Description

Hi Matthew: {color:red} First of all , my id kalon has no permission to create new issue, I had the permission several day ago..what's the reason?{color} You know that Zend_Form has implemented __clone() magic method to support a "senseful" clone operation.Zend_Form knows the fact that clone operation will not copy properties with type of Object , and this fact cause the result clone operation is not do what we expect sometimes. Although __clone in Zend_Form also clone all elements in this form and it's subform and displayGroup , but elements object are just parts of object properties(including decorator,translator,view and so on) in Zend_Form.If we set any object properties or array properties with object values before we clone this form,the result form will not absolutely independent with the previous form.They will hold the same object references with each other.Look over this code:


$form = new Zend_Form();
$form->addDecorator(new Zend_Form_Decorator_Label());
$newForm = clone $form; 
echo $form->getDecorator('Label');
echo $newForm->getDecorator('Label');

This will output: Object id #14 Object id #14

form and newForm share one Decorator Label, I think this is not the effection we want.Although this is just a simple example, it shows to us we cant use clone in Zend_From safely. The way to solve this problem is to use "deep clone" which can copy properties with type of object ,while the PHP clone operation not.See more about deep clone in PHP5, go ahead my article -- http://www.phpthink.com/show-3-1.html
(If you dont know Chinese , just put attention to the PHP code)

Now that we know that PHP function serialize() and unserialize() can help us to do deep clone , we can implement
deepClone() method like this:


public function deepClone()
{
    return unserialize(serialize($this)); 
}

Try the previous code with this deepClone() method:


$form = new Zend_Form();
 $form->addDecorator(new Zend_Form_Decorator_Label());
$newForm = $form->deepClone(); 
echo ($form->getDecorator('Label'));
echo '
'; echo ( $newForm->getDecorator('Label'));

Then output: Object id #14 Object id #30

This is the effection we want.

Since __clone() method is published in use , you cant disable it.I've been try my best to find a way by write some unrealistic code in __clone() to make the clone operation has the same effection with deep clone , but failed.

Hope this issue useful.If I've made mistakes in this post,please point out to me .thanks.

(I found a related issue http://framework.zend.com/issues/browse/ZF-4720 , the way to slove this problem is use deep clone)

Comments

What would be the advantage over cloning each element manually (in e.g. a clone() or deepClone() method)?

Just ran into the exact same problem.

After cloning a Zend_form_SubForm, the elements of the original SubForm where still using the same instance of Zend_Form_Decorator_Label (for instance).

I had to deep-clone (using : unserialize(serialize($this))) to have a proper clone of my SubForm.