February 20, 2009

Singleton Class, Object Cloning and Object Foreach

After the lunch we (Anand, Avlesh, Jaimin, Ashish, Aakash and yours truly) have a light hearted discussion about object and classes. We were wandering if we can clone a singleton class object? Obviously we all differ with others opinion and finally draw the same conclusion that logically you can clone a singleton class object. This is something disappointing for programmer like me who loves to write singleton class to implement single access point, but thankfully in php generally we are not sharing anything between two processes so the threat is really less.

Returning to my desk I wrote a small script to verify my understanding.

class SimpleClass

{

public $var3 = 1;

public function __toString(){

return strval($this->var3);

}

}

class TestSingletonCloning

{

static $classInstance;

public $var1;

public $var2 = 'value 2';

private function TestSingletonCloning()

{

$this->var1= new SimpleClass();

$this->var2 = 'value 2';

}

public static function init()

{

if(!isset(TestSingletonCloning::$classInstance) || empty(TestSingletonCloning::$classInstance) )

{

TestSingletonCloning::$classInstance = new TestSingletonCloning();

}

$inst = & TestSingletonCloning::$classInstance;

return $inst;

}

}

$obj1 = TestSingletonCloning::init();

$obj2 = TestSingletonCloning::init();

$obj3 = clone $obj1;

$obj3->var1->var3 ++;

$obj3->var2 = 'value 3';

var_dump($obj1);

var_dump($obj2);

var_dump($obj3);

After executing the piece of code I got result like following

object(TestSingletonCloning)#1 (2) {
  ["var1"]=>
  object(SimpleClass)#2 (1) {
    ["var3"]=>
    int(2)
  }
  ["var2"]=>
  string(7) "value 2"
}
object(TestSingletonCloning)#1 (2) {
  ["var1"]=>
  object(SimpleClass)#2 (1) {
    ["var3"]=>
    int(2)
  }
  ["var2"]=>
  string(7) "value 2"
}
object(TestSingletonCloning)#3 (2) {
  ["var1"]=>
  object(SimpleClass)#2 (1) {
    ["var3"]=>
    int(2)
  }
  ["var2"]=>
  string(7) "value 3"
}

It is a desired result that I got. Hurrah!!! We have successfully cloned the object of the singleton class. As object Cloning bypasses the constructor call by replicating the object map ( or what ever lies beneath your object)

In PHP the cloning is a shallow copying by default like most of OO languages. So the cloned object points to the same object referred by $val1.Any modification in $var1 of clone Object will affect the object referred by $var1 of the original Object. If desire to change this behavior implement deep copying logic in the magic method __clone of the singleton class. That definitely not solves the problem of having multiple object versions of a singleton class. If you like to stop developer to clone your singleton class, you can throw an exception within __clone function .

Now going by the definition of PHP foreach the last solution, suppose to fail you if you try to iterate over the singleton object using a foreach outside of the class. But it will not, because your object which is supposed to be cloned before iteration, is actual shallow copied via an implementation other than Cloning. So the copying process never calls the __clone method of you singleton class . Try this out before dumping all…

foreach($obj1 as $key => $value) {

if($key=='var1')

$obj1->var1->var3 ++;

echo "$key => $value
";

}

Finally some relief for my soul.



(c) Sourav Ray Creative Commons License

No comments:

Post a Comment