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

February 17, 2009

Favicon for I-Code Today


As this blog is gaining popularity (average 240 unique users per day form 11th Feb ), I thought now it should have an unique Favicon .
I tried to keep the color pallet inline with the blog color.

Dear Readers... do I have to say .. "I am looking for your feedback!". Thank you guys.. for visiting this blog :)


(c) Sourav Ray Creative Commons License

February 11, 2009

PHP array, foreach loop with references and no block-scope – a killer recipe

Today morning I was browsing through my collection ridiculous php bugs ( I have 20+ such code snippet now) and my eyes got stuck to this problem. I cannot remember from where I got this one but surely it’s a jewel in my collection.

Let give a look to the original code
<?php

   $arr = array('A', 'B', 'C', 'D', 'E');
   foreach ($arr as &$val) {}
   foreach ($arr as $val) {}
   var_dump($arr);

?>

The problem is that the var_dump gives a result

array(5) {
  [0]=>
  &string(1) "A"
  [1]=>
  &string(1) "B"
  [2]=>
  &string(1) "C"
  [3]=>
  &string(1) "D"
  [4]=>
  &string(1) "D"
}

Shocked! Aaha… who screwed up your array? Apparently it’s your references
and variable scopes. You get it right but you will be biased if you don’t
criticize the lack of block-scope in php.
In the first foreach block we are assigning reference of the each element
to $val. Thus at the end of the first foreach loop $val actually a reference
to the final index of array $arr.
Now as there is no concept of block-scope in php, the $val will retain the
reference to the final index $arr at the start of the second loop (pathetic!).
 We can simply represent the situation as bellow

<?php

   $arr = array('A', 'B', 'C', 'D', 'E');
   $val = &$arr[4] ;
   foreach ($arr as $val) {}
   var_dump($arr);

?>

Now doing a var_dump of $arr inside the second foreach loop gives us the
following result.
array (
  0 => 'A',
  1 => 'B',
  2 => 'C',
  3 => 'D',
  4 => 'A',
)

array (
  0 => 'A',
  1 => 'B',
  2 => 'C',
  3 => 'D',
  4 => 'B',
)

array (
  0 => 'A',
  1 => 'B',
  2 => 'C',
  3 => 'D',
  4 => 'C',
)

array (
  0 => 'A',
  1 => 'B',
  2 => 'C',
  3 => 'D',
  4 => 'D',
)

array (
  0 => 'A',
  1 => 'B',
  2 => 'C',
  3 => 'D',
  4 => 'D',
) 
So it is clear now the second foreach loop actually assigns value of
each index one by one to the index referred by $val (final index).
 Now try out this solution 

<?php

   $arr = array('A', 'B', 'C', 'D', 'E');
   foreach ($arr as &$val) {}
   unset($val);
   foreach ($arr as $val) {}
   var_dump($arr);

?>

IT WORKS :)

(c) Sourav Ray Creative Commons License