The scenario: fetch an email template from the database, and loop through a list of recipients, personalising the email for each.
My email template is returned as a nested object. It might look a little like this:
object(stdClass) {
["title"] => "Event Notification"
["sender"] => "[email protected]"
["content"] => object(stdClass) {
["salutation"] => "Dear %%firstname%%,"
["body"] => "Lorem ipsum %%recipient_email%% etc etc..."
}
}
Then I loop through the recipients, passing this $email object to a personalise() function:
foreach( $recipients as $recipient ){
$email_body = personalise( $email, $recipient );
//send_email();
}
The issue, of course, is that I need to pass the $email object by reference in order for it to replace the personalisation tags - but if I do that, the original object is changed and no longer contains the personalisation tags.
As I understand, clone won't help me here, because it'll only create a shallow copy: the content object inside the email object won't be cloned.
I've read about getting round this with unserialize(serialize($obj)) - but everything I've read says this is a big performance hit.
So, two finally get to my two questions:
Using the assignment operator to copy an object In PHP, a shallow copy of the object can be created by using the keyword clone, and a deep copy of the object can be created by using the method __clone().
Deep copies duplicate everything. A deep copy, meaning that fields are de-referenced: rather than references to objects being copied, new copy objects are created for any referenced objects, and references to these placed in new object. Shallow copies duplicate as little as possible.
clone() is indeed a shallow copy. However, it's designed to throw a CloneNotSupportedException unless your object implements Cloneable . And when you implement Cloneable , you should override clone() to make it do a deep copy, by calling clone() on all fields that are themselves cloneable.
The clone keyword is used to create a copy of an object. If any of the properties was a reference to another variable or object, then only the reference is copied. Objects are always passed by reference, so if the original object has another object in its properties, the copy will point to the same object.
You could add a __clone()
method to your email class. Which is automatically called when an instance of this class is cloned via clone(). In this method you can then manually add the template.
Example:
class Email {
function __clone() {
$this->template = new Template();
}
}
.
unserialize(serialize($object)); // would be another solution...
Another more generic and powerful solution: MyCLabs\DeepCopy.
It helps creating deep copy without having to overload __clone
(which can be a lot of work if you have a lot of different objects).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With