Showing posts with label object. Show all posts
Showing posts with label object. Show all posts

Friday, June 5, 2009

Object references, assignment and as function arguments

As of PHP5, objects are treated REFERENCE ! (same behaviour as C++ and Java)

1) assignment from an objects to another copies the reference, not the content !!
What is a reference ? it's a variabile/object that ONLY contains the pointer to the effective object in the memory. As I said in a previous post, the assigment instruction copy ONLY the value (pointer) of the object-pointer, it doesn't duplicate the content (members) of the class !
Let's demonstrate with an example, using the unset() function

class A { public $foo = 1; }
$a = new A;
$aRef = $a;
unset($aRef ); //delete ONLY the object-pointer !
print $a->foo; //print 1. This is the proof that $aRef is only a pointer

$aRef = $a;
unset($aRef ->foo); //through the object-pointer $c, it delete the real content !!
print $a->foo; //Notice: Undefined property !! This is the proof that $aRef is not a copy !!

2) objects are passed to functions by REFERENCE !

class A { public $foo = 1; }
$a = new A;
function foo($obj) {
$obj->foo = 2;
unset($obj); // delete local reference (that is a copy), no problem !
}
foo($a);
echo $a->foo; //2 ! this is the proof that the argument is passed as reference (the function doesn't return any value !) and not as a copy (the value outside the function is changed!)


Note 1: arrays are passed by copy, unless the function declare the argument as reference with "&"
function arrayDeleteFirst(&$ar) { unset($ar[0]); }

Note2: references work with variables as well
$a = 1;
$b = &$a;
$b = 2;
unset($b); //no problem. It deletes the reference, not the variabile pointed !
print $a; //2

the "==" and the "===" operators

PHP has two types of comparison operators: "==" and "===" ( and respectively "!=" and "!==" ).

Variables

"==" offers a simple comparison of the content of variables, skipping the type (int, string, boolean,...) of the variables.
The following expression are equivalent to the operator "==":
  • false
  • 0
  • ""
  • ''
  • "0"
  • 0.0
  • -0
  • !1
  • array()
  • $i // where $i is not initialized (notice generated)
  • strpos("abcd","a") // (*)
The following expression are the same for the operator "==", as well
  • true
  • 1
  • "a"
  • 0.1
  • -1
  • array(1)
  • !0
  • " " //space
Differently, for the "===" operator, the two expression are equal ONLY IF the contents and THE TYPES are the same. The items in both list are different for the operator "===".
Note also these other cases:
  • 0===0.0 //int and double : false !
  • 1.5===1+0.5 //true ! 1 promoted to double 1.0
  • $i =0; $i===0 //true
  • $j===$m //true. ($j and $m are not initialized, notice generated)
(*) strpos($str, $search) [manual] returns the position of $search in the string $str, or returns "false" if not. This function is common used to control the existence of a string in another string. To do it, remember to use the operator "!==" !! If the $search is in position 0, the function returns 0 (and 0==false) !! In php code:

print strpos("abcd","a")?"exists":"not exists"; //not exists -> SEMANTIC ERROR !!!
print strpos("abcd","a")!=false?"exists":"not exists"; //not exists -> SEMANTIC ERROR !!!
print strpos("abcd","a")!==false?"exists":"not exists"; // exists -> CORRECT !


objects
Similarly, for the "==" operator, two objects are equal if they are instantiated from the SAME class and the comparison of their elements (using "==" operator, not "===") is true

class A
{
private $v;
pub
lic function __construct($v) { $this->v = $v; }
}

Now, read carefully the following line. Two object of the same class are equal for the operator "=="
new A( array(true,1.0) ) == new A(array(1,1)) // true !!
new A( array() ) == new A(array(1,2,3)) // true !!

Differently, for the "===" operator, the two object equal ONLY IF they refer to the SAME OBJECT!!

new A( 1 ) === new A(1); //false
$a = new A( 1 );
$aCopy = $a;
$aClone = clone $a;
$a === $aCopy; // true ! the two references point to the same object !
$a === $aClone; //false ! a clone is a different object !



Object iteration 2/2

about object iteration, in php5 it's possibile to use Iterators (similar to Java and C++).

Iterator is a PHP5 default interface that includes the public methods (to implement):
  • mixed current ( ) // returns the current element in the loop ($key)
  • scalar key ( ) // returns the current key in the loop ($val)
  • void next ( ) // called for obtain the next element
  • void rewind ( ) // rewind iterator to the 1st element (called at the beginning)
  • boolean valid ( ) // check if the current position is valid
class MyIt implements Iterator
{
public function current() {}
public function
key() {}
public function
next() {}
public function
rewind() {}
public function
valid() {}
}

Example (minimal):
We can create our class, keeping data in a private member and let these methods to access it.
We will use the php default function reset(), current(), next(), current() that easily allow to manage the element pointer in an array.

class A implements Iterator
{
private $ar = array();
public function
__construct($ar) { $this->ar = $ar; }
public function
current() {return current($this->ar);}
public function
key() {return key($this->ar);}
public function
next() { next($this->ar);}
public function
rewind() {reset($this->ar);}
public function valid() {return current($this->ar)!== false;}
}

$a = new A( array(1,2,3,4) );
foreach (
$a as $k=>$v)
{
print
" $k=>$v ";
}
//output: 0=>1 1=>2 2=>3 3=>4

Note: this is an example, we don't need to implement an iterator for a simple array. Pratically, we'll use an interator when we have different type of data (example: event calendar with a collection of events = customized objects).

IteratorAggregate
We've just built an implementation of an iterator for a class containing an array.
Now, let's suppose that we have a class B which manages his own array with other functionalities. If we want to use the previous iterator in the class B, we don't need to reimplement the interface Iterator.
It's enough to implement the class IteratorAggregate and his method getIterator() which returns a object which implements Iterator (the class A).

minimal example:

class B implements IteratorAggregate
{
private $bArray = array(6,7,8); //not a good/useful practice, but it's a minimal example !!
public function getIterator()
{
return new
A($this->bArray);
}
}


foreach (new
B() as $k=>$v)
{
print " $k=>$v ";

} //0=>6 1=>7 2=>8



Object iteration 1/2

the construct foreach in PHP5 supports also object, in addition to arrays.

foreach($object as $key=>$val)
{
//$key will be equal to the nth member name
//$val will be equal to the nth member value
}

Which members are visibile ? it depends on the "foreach" position !
  • inside the class ($this is the object): all the members are visibile
  • outside the class: only public members are visible
  • inside an inherited class: public and protected
Example:

class A
{
public $a;
public
$b;
private
$p;
public function
__construct($a, $b, $p){
$this->a = $a;$this->b = $b; $this->p = $p;
}
public function
f()
{

foreach(
$this as $k=>$v)

{print "$k => $v \n"; }
}
}

$a = new A(1,2,3);

foreach(
$a as $k=>$v)
{
print "$k => $v \n";
} //a => 1 b => 2

$a->f(); //a => 1 b => 2 p => 3

Thursday, June 4, 2009

PHP5: object references, object cloning and __clone()

Let's make a simple class with a value (default=1), set and get methods

class Obj
{
private $var=1;
public function
setVal($var) { $this->var = $var; }
public function getVal() { return $this->var; }
}

Following, another class that includes the previous one (Or better, it includes a reference to the previous class, and the object will be instantiated by the constructor)

class A
{
private $obj; //reference to the previous class
private $i=1; //internal variabile
public function __construct() { $this->obj = new Obj(); }
//set the private properties and the val of the internal object !
public function
setAll($v) { $this->obj->setVal($v); $this->i =$v; }
public function
getObj() { return $this->obj->getVal(); }
public function
getI() { return $this->i; }
function
__clone()
{
$this->obj = clone $this->obj;
}
}

OBJECT ASSIGN (IT'S NOT A COPY)
Now we instantiate a class and assign its reference to other variables

$a = new A();
$aRef = &$a; // REFERENCE
$aCopy = $a; // REFERENCE as well, the same as before!!!

$a->setAll(2);

print
$aRef-> getObj(); //2
print $aRef->getI();//2
print $aCopy-> getObj();//2
print $aCopy->getI();//2

CLONING
to copy all the elements of an object to another reference/variabile, you must clone it, using "clone" keyword.
$a = new A();
$aClone = clone $a; //CLONE
$a->setAll(2); //the cloned object ($aClone) won't be modified !

print
$aClone->getI(); // "1"
print $aClone->getObj(); //"1"
thanks to the overriding __clone() method,
otherwise "2"

 

PHP and tips|PHP