diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 7b7389b5f7962..3df49b6c20786 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -1467,7 +1467,7 @@ // warehouse $result = $object->setWarehouse(GETPOST('warehouse_id', 'int')); } elseif ($action == 'update_extras') { - $object->oldcopy = dol_clone($object); + $object->oldcopy = dol_clone($object, 2); // Fill array 'array_options' with data from update form $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml')); diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 9827414c3ff96..e9ae5bdfe15ae 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1145,29 +1145,43 @@ function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0) } /** - * Create a clone of instance of object (new instance with same value for properties) - * With native = 0: Property that are reference are also new object (full isolation clone). This means $this->db of new object is not valid. + * Create a clone of instance of object (new instance with same value for each properties) + * With native = 0: Property that are reference are different memory area in the new object (full isolation clone). This means $this->db of new object may not be valid. * With native = 1: Use PHP clone. Property that are reference are same pointer. This means $this->db of new object is still valid but point to same this->db than original object. + * With native = 2: Property that are reference are different memory area in the new object (full isolation clone). Only scalar and array values are cloned. This means $this->db of new object is not valid. * * @param object $object Object to clone - * @param int $native 0=Full isolation method, 1=Native PHP method + * @param int $native 0=Full isolation method, 1=Native PHP method, 2=Full isolation method keeping only scalar and array properties (recommended) * @return object Clone object * @see https://php.net/manual/language.oop5.cloning.php */ function dol_clone($object, $native = 0) { - if (empty($native)) { + if ($native == 0) { + // deprecated method, use the method with native = 2 instead $tmpsavdb = null; if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') { $tmpsavdb = $object->db; - unset($object->db); // Such property can not be serialized when PgSql/Connection + unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection') } - $myclone = unserialize(serialize($object)); // serialize then unserialize is hack to be sure to have a new object for all fields + $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields - if ($tmpsavdb) { + if (!empty($tmpsavdb)) { $object->db = $tmpsavdb; } + } elseif ($native == 2) { + // recommended method to have a full isolated cloned object + $myclone = new stdClass(); + $tmparray = get_object_vars($object); // return only public properties + + if (is_array($tmparray)) { + foreach ($tmparray as $propertykey => $propertyval) { + if (is_scalar($propertyval) || is_array($propertyval)) { + $myclone->$propertykey = $propertyval; + } + } + } } else { $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable) }