Metody magiczne w PHP, część druga

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…

Dodaj komentarz