I have an object that represents the result of a calculation. It also stores the time (runtime) it took to compute that result.
In some cases it is faster to clone the previous object instead of recalculating everything again (for example, when the same input parameters would produce the same result).
However, when cloning the object, the runtime must not be copied. The cloned object should have a new runtime value, based on the time it took to determine that the same result can be reused.
Here is a simplified example:
class Object
{
protected $runtime;
public function getRuntime()
{
return $this->runtime;
}
public function doSome(/*...*/)
{
$start = microtime(true);
// ... the heavy work ...
// ...
$this->runtime = microtime(true) - $start;
}
}
$objects = [];
while (/*...*/) {
if (count($objects) > 0) {
$start = microtime(true);
if (/*check if would get the same result as the previous one*/) {
$object = clone end($objects);
// MUST change the runtime here on the clone
// but i should not make :runtime public
$object->runtime = microtime(true) - $start; // :(
$objects[] = $object;
continue;
}
}
$object = new Object();
$object->doSome(/*...*/);
$objects[] = $object;
}
How could I clone the previous object and update the protected runtime value on the clone without making that property public?
I would suggest to put this logic in separated method Object::clone() like this:
class Object
{
protected $runtime;
public function getRuntime()
{
return $this->runtime;
}
public function doSome(/*...*/)
{
$start = microtime(true);
// ... the heavy work ...
// ...
$this->runtime = microtime(true) - $start;
}
public static function clone($clonable, $runtime)
{
$clone = clone $clonable;
$clone->runtime = $runtime; // we can access it since we are in Object scope
return $clone;
}
}
$objects = [];
while (/*...*/) {
if (count($objects) > 0) {
$start = microtime(true);
if (/*check if would get the same result as the previous one*/) {
$object = Object::clone(end($objects), microtime(true) - $start);
$objects[] = $object;
continue;
}
}
$object = new Object();
$object->doSome(/*...*/);
$objects[] = $object;
}
Another option is just to implement setter method for runtime property