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…