Serializacja danych w PHP
MatheW
Serializacja danych w PHP
1 Serializacja danych w PHP
1.1 Serializacja obiektów
1.1.1 Magiczne metody __sleep()
i __wakeup()
1.2 Serializacja a sesje
1.3 Gdzie możemy wykorzystać serializację?
Na początku standardowa, książkowa definicja serializacji (oczywiście z Wikipedii):
Serializacja - w programowaniu komputerów proces przekształcania obiektów, tj. instancji określonych klas, do postaci szeregowej, czyli w strumień bajtów, z zachowaniem aktualnego stanu obiektu. Serializowany obiekt może zostać utrwalony w pliku dyskowym, przesłany do innego procesu lub innego komputera poprzez sieć. Procesem odwrotnym do serializacji jest deserializacja. Proces ten polega na odczytaniu wcześniej zapisanego strumienia danych i odtworzeniu na tej podstawie obiektu klasy wraz z jego stanem bezpośrednio sprzed serializacji.
Serializacja jest bardzo przydatna - dzięki niej możemy zapisać stan obiektu, tablicy czy innej zmiennej do specjalnego ciagu , a następnie przykładowo do bazy danych, czy pliku, lub nawet sesji - a w przyszłości z ów zmiennej skorzystać, co przydaje się np. przy cachowaniu. Innymi słowy jest to zamiana elementu języka programowania w gołe bajty.
Do serializacji możemy użyć naszego własnego mechanizmu, biblioteki do serializacji, lub skorzystać z mechanizmu PHP. W tym artykule zaprezentowana jest metoda dostarczona przez PHP. Możesz napisać swój system serializacji lub skorzystać z innej biblioteki.
Dzięki temu zapisowi możemy w innym skrypcie za pomocą deserializacji wczytać ten obiekt, posiadający wszystkie właściwości, które nadaliśmy mu przed zapisem do zmiennej tekstowej. Niestety serializacja i deserializacja domyślna w PHP zadziała tylko w PHP. Do serializacji pomiędzy językami i systemami użyj innych, bardziej okrojonych w możliwości formatów, np JSON, XML.
Funkcjami za to odpowiedzialnymi są serialize()
oraz unserialize()
, ich użycie prezentuje przykład:
$array= ['value1', 'value2'];
$serializedArray = serialize($array); # serializacja tablicy
$unserializedArray = unserialize($serializedArray); # deserializaja
var_dump($unserializedArray);
Na początku deklarujemy tablicę posiadającą dwa elementy. Następnie serializujemy tablicę funkcją serialize()
i przypisujemy do zmiennej $serializedArray
. Gdybyśmy ją wyświetlili, ujrzelibyśmy:
a:2:{i:0;s:6:"value1";i:1;s:6:"value2";}
Deserializacja nastepuje za pomocą funkcji unserialize()
. Odzyskaną tablicę wyświetlamy i oto co widzimy:
Array
(
[0] => value1
[1] => value2
)
Struktura zmiennej się nie zmieniła - jest to praktycznie ta sama zmienna!
Serializacja obiektów
Serializacja obiektów nie różni się w zasadzie od serializacji innych zmiennych:
class Serialization {
private $field;
/**
* Zapisuje zmienna
*/
public function setField($value) {
$this->field= $value;
}
/**
* Zwraca zmienna
*/
public function getField() {
return $this->field;
}
}
$serialization= new Serialization(); #tworzymy obiekt
$serialization->setField('value'); #przypisujemy polu wartość value
$serializedObject= serialize($serialization); #serializujemy
$unserializedObject= unserialize($serializedObject); #deserializujemy
echo $unserializedObject->getField(); #wyswietlamy pole deserializowanego obiektu
Jak widzimy mamy tu klasę Serialization, z polem $field. Po utworzeniu obiektu zapisujemy polu wartosc value, następnie poddajemy serializacji i deserializacji i wyświetlamy pole - jest to ta sama wartość!
Jednak gdy chcemy użyć serializowanej zmiennej w innym skrypcie należy pamiętać, że musi być w nim zawarty kod klasy tego obiektu!
Magiczne metody __sleep()
i __wakeup()
Obiekty mają tą dogodność, że mogą dowolnie zmieniać własne dane podczas serializacji i deserializacji, za pomocą metod magicznych.
Pierwszą z nich jest metoda o nazwie __sleep()
. Wywoływana jest ona automatycznie podczas serializacji obiektu i może służyć do manipulowania danymi, które muszą zostać zmodyfikowane przed poddaniem obiektu serializacji. Funkcja powinna zwrócić tablicę, której elementy będą nazwami pól obiektu, które mają zostać w nim zachowane.
Funkcja __wakeup()
jest wywoływana przy deserializacji obiektu. Może być przydatna np. do ponownego połączenia z bazą, otwarcia pliku itd.
class Serialization {
private $time;
public function __sleep() {
$this->time= time(); #zapis aktualnego czasu
return array_keys(get_object_vars($this));
}
public function __wakeup(){
echo $this->time; #wyswietlamy czas serializacji
}
}
$serialization= new Serialization(); #tworzymy obiekt
$serializedObject= serialize($serialization); #serializujemy
$unserializedObject= unserialize($serializedObject); #deserializujemy
Efektem kodu jest wyświetlenie uniksowego znacznika czasu, w którym nastąpiła serializacja. W przykładzie podczas serializacji zapisujemy czas, w którym obiekt został jej poddany, a podczas deserializacji jest on wyświetlany.
Warto zwrócić uwagę na linię
return array_keys(get_object_vars($this));
get_object_vars()
zwraca nam tablice składająca sie z nazw pól obiektu i ich wartości, a array_keys zwraca tejże tablicy indeksy, przez co dostajemy nazwy wszystkich pól obiektu - są one niezbedne do poprawnej serializacji.
Serializacja a sesje
Sesje są ściśle związane z serializacją - podczas zapisu zmiennej do sesji, jest ona przechowywana właśnie jako serializowany string. Podczas rozpoczecia sesji obiekty są deserializowane, a podczas zakończenia parsowania kodu zmienne sesyjne są poddawane serializacji.
Najlepiej zobrazuje to przykład, który w końcu zaprezentuje praktyczne wykorzystanie serializacji:
session_start();
class DBConnector {
public $connection, $user, $pass, $host;
public function connect() {
if (!$this->connected)
$this->db= new mysqli($this->host, $this->user, $this->pass); #polaczenie sie z baza danych
}
/**
* Stwier dza czy jestesmy juz polaczeni z baza danych
*/
public function connected() {
return $this->db instanceof mysqli; #jezeli zmienna jest implementacja klasy mysqli
}
public function __sleep() {
$this->db->close(); #rozlaczenie
$this->db= null; #wyczyszczenie zmiennej
echo 'Rozłączono z bazą danych';
return array_keys(get_object_vars($this));
}
public function __wakeup() {
echo $this->connect(); #laczymy
}
}
$connector= new DBConnector();
$connector->host= 'localhost';
$connector->user= 'user';
$connector->pass= 'password';
$connector->connect();
$_SESSION['connector']=$connector;
W przykładzie mamy klasę łączącą się z bazą danych, oraz przechowującą identyfikator połączenia. Po zapisie jej do zmiennej sesyjnej oraz zakończeniu skryptu zostaje ona poddana serializacji, czego efektem będzie rozłączenie się z bazą danych oraz wyświetlenie komunikatu.
Teraz gdy odpalimy inny plik, będziemy mogli skorzystać z tych danych i korzystać z bazy danych:
require_once('DBConnector.class.php');
session_start();
if($_SESSION['connector']->connected()) echo 'Jest połączenie z bazą danych';
Pamiętajmy by załączyć klasę, której implementacją jest obiekt przed rozpoczęciem sesji - inaczej wyświetli nam się błąd.
Gdzie możemy wykorzystać serializację?
Serializacja przydaje się między innymi podczas cachowania danych - wielokrotny pobór danych z bazy danych,a następnie ich przetwarzanie jest powolne, a wraz z obciążeniem skryptu przez użytkowników wzrasta jeszcze bardziej. Zapisując serializowane dane do pliku i korzystanie z nich znacznie usprawni prace skryptu. Serializacja przyda się pewnie też przy rozbudowanych formularzach, składających się z kilku stron - wtedy korzystamy z obiektów w sesji.