Jakiś czas temu przedstawiłem pierwszą część z serii artykułów opisujących metody magiczne w PHP. Dzięki ich zastosowaniu możemy uzyskać wiele dodatkowych możliwości podczas korzystania z obiektów. Dziś kolej na opisanie następnych z nich: __toStrnig(), __clone(), __sleep() oraz __wakeup().
Metoda __toString
Niniejsza metoda zwraca tekstową reprezentację obiektu i zostanie wywołana w momencie, gdy będziemy chcieli go wyświetlić, na przykład przy pomocy instrukcji echo lub print. Gdy nie zdefiniujemy __toString(), efektem takiego działania będzie błąd i zatrzymanie skryptu:
Catchable fatal error: Object of class MyClass could not be converted to string in /sciezka/do/skryptu/skrypt.php on line 13
Ważną rzeczą jest, że metoda musi na koniec działania zwracać wartość tekstową. Jeśli będzie to liczba, tablica lub obiekt, wygenerowany zostanie błąd. Można w takim przypadku skorzystać z konwersji typów (rzutowania). Na poniższym skrypcie przedstawiono zastosowanie omawianej metody:
class MyClass
{
private $variable;
public function __construct($parametr)
{
$this->variable = $parametr;
}
public function __toString()
{
return $this->variable;
}
}
$object = new MyClass("abc");
echo $object;
Efektem działania skryptu będzie po prostu wyświetlenie zawartości właściwości $variable, czyli abc.
Metoda __clone()
W PHP5 w odróżnieniu od wersji 4 wszystkie obiekty reprezentowane są przez referencję. Nie jest więc możliwe bezpośrednie tworzenie kopii obiektów. Poniższy kod spowoduje przypisanie pod $anotherObject referencji do $object:
$object = new MyClass(); $anotherObject = $object;
W takim przypadku zmiana jednego z obiektów spowoduje więc jednoczesną zmianę drugiego.
Aby utworzyć kopię, musimy skorzystać z instrukcji clone:
$object = new MyClass(); $anotherObject = clone $object;
Utworzenie obiektu w powyższy sposób spowoduje, że w przypadku jakiejkolwiek modyfikacji, zmieniamy tylko jeden z nich.
Metoda __clone() jest wywoływana właśnie podczas klonowania obiektu. Dzięki temu możemy wprowadzić w nim określone zmiany. Przedstawiono to na poniższym przykładzie:
class MyClass
{
private $id;
private $variable;
public function __construct($variable)
{
$this->id = md5(rand());
$this->variable = $variable;
}
public function __clone()
{
$this->id = md5(rand());
}
}
$object = new MyClass("abc");
$object = clone $object;
var_dump($object);
var_dump($object);
Wynik działania skryptu będzie następujący:
object(MyClass)#2 (2) {
["id":"MyClass":private]=>
string(32) "d204e0411e7921f0b468ddb52ea87fc7"
["variable":"MyClass":private]=>
string(3) "abc"
}
object(MyClass)#2 (2) {
["id":"MyClass":private]=>
string(32) "d204e0411e7921f0b468ddb52ea87fc7"
["variable":"MyClass":private]=>
string(3) "abc"
}
Po utworzeniu obiektu $object z podaniem jednego parametru, następuje jego sklonowanie. Konstruktor klasy przypisuje przekazany parametr do odpowiedniej właściwości oraz dodatkowo generuje unikalny identyfikator. Jak jednak widać metoda __clone() wywoływana podczas kopiowania obiektu generuje nowy identyfikator. Widać to wyraźnie po wyświetleniu zawartości obiektów: oba mają tę samą wartość zmiennej $variable, jednak różne $id.
Metody __sleep() i __wakeup()
Kolejne dwie metody magiczne wywoływane są w przypadku serializacji obiektów. Polega ona (tak samo jak w przypadku tablic), na przekształceniu struktury danych na postać łańcucha znaków, możliwego do ponownego przekształcenia w obiekt. Wykorzystuje się do tego celu funkcje serialize() oraz unserialize().
Dzięki metodom __sleep() oraz __wakeup() możemy dokonać modyfikacji obiektu oraz wybrać właściwości, które będą poddane serializacji. Metody te nie przyjmują żadnych parametrów, ale __sleep() powinna zwracać indeksowaną tablicę zawierającą nazwy właściwości, jakie poddane zostaną operacji.
Na poniższym przykładzie przedstawiono działanie metod:
class MyClass
{
private $id;
private $variable1;
private $variable2;
public function __construct($variable1, $variable2)
{
$this->id = md5(rand());
$this->variable1 = $variable1;
$this->variable2 = $variable2;
}
public function __sleep()
{
return array("variable1");
}
public function __wakeup()
{
$this->id = md5(rand());
}
}
$object = new MyClass(123, "abc");
$object_s = serialize($object);
$object_u = unserialize($object_s);
echo "Obiekt:";
var_dump($object);
echo "Obiekt po serialize():";
var_dump($object_s);
echo "Obiekt po unserialize():";
var_dump($object_u);
Efekt działania skryptu będzie następujący:
Obiekt:object(MyClass)#1 (3) {
["id":"MyClass":private]=>
string(32) "c57ec22b3055e619b765e52dbe9dc5f1"
["variable1":"MyClass":private]=>
int(123)
["variable2":"MyClass":private]=>
string(3) "abc"
}
Obiekt po serialize():string(50) "O:7:"MyClass":1:{s:18:"MyClassvariable1";i:123;}"
Obiekt po unserialize():object(MyClass)#2 (3) {
["id":"MyClass":private]=>
string(32) "857590827074cb64b4c0df198ecdc431"
["variable1":"MyClass":private]=>
int(123)
["variable2":"MyClass":private]=>
NULL
}
Na początku tworzony jest obiekt, którego konstruktor przypisuje do dwóch właściwości przekazane parametry, oraz dodatkowo ustala pseudolosowy identyfikator. Następuje później serializacja obiektu, która zmienia jego postać na łańcuch znaków. W tym momencie wywoływana jest metoda __sleep(), która wybiera tylko jedną z właściwości do przechowania. W kolejnym kroku wykonywana jest czynność przywrócenia obiektu, w wyniku której uruchomiona zostaje __wakeup(). Dzięki temu $variable1 zostaje odzyskana, jednak druga właściwość $variable2 już nie (została pominięta w __sleep()). Dodatkowo wylosowany zostaje nowy identyfikator.
Ciąg dalszy nastąpi…
