Conservons nos variables avec serialize()

Formation

En Semi-présenciel Paris

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Méthodologie

    En semi-présentiel

  • Lieu

    Paris

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Les sites et dates disponibles

Lieu

Date de début

Paris ((75) Paris)
Voir plan
7 Cité Paradis, 75010

Date de début

Consulter

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Le programme

Introduction du cours

Avant d'aborder la lecture de ce tutoriel, vous devez maîtriser les notions suivantes :

  • variables et types de variables ;

  • arrays ;

  • fonctions ;

  • programmation orientée objet en PHP ;

  • SQL (un minimum).

À certains moments, on apprécierait de pouvoir enregistrer un array en intégralité (c'est-à-dire avec les clefs associées aux valeurs) en base de données, ou encore dans un fichier.
Des possibilités s'offrent alors à nous : on pourrait, par exemple dans le cas d'un fichier, parcourir l'array via un foreach, afin d'écrire ligne par ligne chaque élément… Mais cet exemple devient impossible dans le cas d'un array multidimensionnel, par exemple.

Un array multidimensionnel est un array contenant plus d'une dimension. Par exemple, $array[X][Y] signifie qu'on a un array à deux dimensions, alors que $array[X] nous indique un array à une seule dimension…
Plus généralement, un array multidimensionnel serait un array contenant un array (qui peut lui-même contenir un array…).

On pourrait alors utiliser la récurrence… Et on se rend alors compte que cela fait beaucoup de bruit pour rien.
En effet, il existe une fonction bien particulière et ô combien puissante dans ce genre de cas en PHP : serialize().

Le principe

serialize() ne fonctionne correctement que depuis PHP 4, mais je ne pense pas que vous soyez encore sous une version antérieure… Si c'est le cas, je vous conseille vivement de vous mettre à jour, il en est plus que temps !

Le principe de serialize() est simple, et bien résumé dans la documentation PHP :

Citation : Documentation PHP

serialize() retourne une chaîne contenant une représentation linéaire de value, pour stockage.
C'est une technique pratique pour stocker ou passer des valeurs de PHP entre scripts, sans perdre ni leur structure, ni leur type.

Ah, c'est simple et bien résumé, cela ?

Eh bien mine de rien, oui. Cela signifie simplement qu'on peut « transtyper » une variable, quel que soit son type, en une chaîne de caractères.

Notez les guillemets autour du mot transtyper. En effet, le principe de serialize() n'est pas de faire un transtypage classique, mais bien une linéarisation qui conserve le type (et donc les informations) de la variable originale.

Pour comprendre simplement, testons ce code :

<?php $notes = array(7,3,8,9); // Formation d'un array pour la forme echo serialize($notes); // echo du résultat de serialize() sur cet array ?>

Citation : Affichage

a:4:{i:0;i:7;i:1;i:3;i:2;i:8;i:3;i:9;}

Un echo suffit, car serialize() retourne une chaîne de caractères (en tout cas, s'il n'y a aucune erreur).
Cela nous affichera… quelque chose de peu compréhensible, certes. Mais on arrive à voir que nos valeurs sont toujours là et dans le même ordre, même si c'est sous une forme différente.

Testons cet autre code, à présent :

<?php $notes = array('maths'=>7,'anglais'=>3,'svt'=>8,'algo'=>9); echo serialize($notes); ?>

Citation : Affichage

a:4:{s:5:"maths";i:7;s:7:"anglais";i:3;s:3:"svt";i:8;s:4:"algo";i:9;}

Encore quelque chose de peu compréhensible… Mais on retrouve encore nos valeurs, et aussi les clefs !

Mais comment ça marche ?

Pour comprendre, testons ce code :

<?php $entier = 17; $bool = TRUE; $float = 0.75669; $chaine = "ma chaine"; $array = array(0,4,7,3); $array2 = array('truc'=>'machin', 'chose'=>8, 9=>'youpie'); echo serialize($entier); echo '<br />'; echo serialize($bool); echo '<br />'; echo serialize($float); echo '<br />'; echo serialize($chaine); echo '<br />'; echo serialize($array); echo '<br />'; echo serialize($array2); ?>

Citation : Affichage

i:17;
b:1;
d:0.75668999999999997374544591366429813206195831298828125;
s:9:"ma chaine";
a:4:{i:0;i:0;i:1;i:4;i:2;i:7;i:3;i:3;}
a:3:{s:4:"truc";s:6:"machin";s:5:"chose";i:8;i:9;s:6:"youpie";}

serialize() prend la variable, et cherche d'abord son type. Cette définition de type sera conservée (i pour integer, b pour booléen, d pour double, s pour string et a pour array). Selon ce type, il va chercher le nombre d'éléments ou non. Ce nombre d'éléments peut être la longueur d'une chaîne de caractères ou le nombre d'éléments d'un tableau.
Ensuite, serialize() définit le contenu selon ce type. Dans le cas d'un entier, le contenu ne change pas. Serializer un entier reviendrait donc à grossir juste la taille (en mémoire) prise par la variable… Oublions donc les entiers.
Pour un booléen, serialize() traduit la valeur en entier (TRUE devient 1 et FALSE devient 0) par transtypage classique. On revient à la même problématique qu'avec les entiers : on évitera de serializer un booléen.
De même pour une chaîne, à noter que serialize() place des guillemets autour des chaînes, ce qui peut être intéressant à savoir dans le cas d'un enregistrement en base de données.
Vous remarquerez sûrement que notre nombre décimal est devenu… quelque peu bizarre. Cela est dû à une mauvaise précision de calcul de serialize() qui n'est réellement pas fait pour traiter des données aussi simples.

La précision de serialize() est indiquée dans le php.ini. Il s'agit de la directive serialize_precision dans PHP Core.

Passons à nos chers arrays !
Il semblerait que serialize() répète la procédure précédente (déterminer le type, puis le nombre d'éléments, puis la valeur…) pour chaque élément. Une dimension d'un array est délimitée par des accolades.
Et les clefs n'en sont pas exemptes et semblent traitées… comme des valeurs simples !

Mais alors, comment différencier les clefs des valeurs ?

C'est là que joue le nombre d'éléments. :)
Si l'on a un seul élément, mais qu'on a deux valeurs dans l'array serializé, c'est qu'il s'agit d'une paire clef/valeur.
De toute façon, tout array est normalement indexé numériquement en interne, par PHP. D'où notre premier affichage.

Et comme on a ainsi une chaîne de caractères (conservant néanmoins parfaitement notre array), on peut facilement la manipuler, pour la transmettre de page en page, l'envoyer en base de données, ou encore l'écrire dans un fichier.

Ah ouais, super… Mais on ne peut rien en faire de cette chaîne de caractères !

Et pof ! Voici unserialize().

Cette superbe fonction peut se résumer en une phrase : elle fait l'inverse de serialize().
En partant d'une chaîne de caractères provenant de serialize(), unserialize() récupère les données et renvoie… les données originales. Concrètement, cela signifie qu'en testant ceci :

<?php $notes = array('maths'=>1,'svt'=>8,'algo'=>6,'philo'=>5); // Un array… $serialized = serialize($notes); // On serialize et on stocke cette chaîne. echo '<pre>'; // Les balises « pre » permettent d'afficher lisiblement un array. print_r(unserialize($serialized)); // On utilise « print_r » pour une bonne raison. echo '</pre>'; ?>

Citation : Affichage

Array
(
[maths] => 1
[svt] => 8
[algo] => 6
[philo] => 5
)

on récupère notre array, intact. :)

Utilisations

On sait donc serializer et deserializer.
Apprenons donc à nous servir de cela, en passant par quelques exemples concrets.

Pour commencer, serializons un array de profondeur inconnue.

La profondeur d'un array, c'est le nombre de dimensions, mais certains disent qu'ils s'agit également du nombre d'éléments. J'ignore quelle définition est la bonne, mais personnellement je préfère dire qu'il s'agit du nombre de dimensions.

<?php $srzed = serialize($array_inconnu); ?> L'enregistrement dans un fichier

On va garder cet array pour la suite. Commençons par tenter de l'enregistrer dans un fichier.

<?php $fh = fopen('test.txt','a+'); // Ouverture d'un fichier en lecture/écriture, en le créant s'il n'existe pas. fwrite($fh,$srzed); // On écrit. fclose($fh); // On ferme. ?>

Quoi de plus simple ?

Notez qu'il reste un problème : si le fichier trouve un caractère spécial (\t, \n…), il va le traduire comme tel. Assurez-vous de vous protéger contre cela, par exemple en doublant le \.

L'utilisation de serialize en barre d'adresse

Un autre exemple, à présent : la transmission via GET.
En effet, une chaîne peut facilement être transmise dans l'URL.
Testons cela :

<?php header("Location:autrepage.php?data=".$srzed); // Une simple redirection, mais avec des données GET. exit; ?>

Ce code générera probablement… une erreur. C'est normal. Certains caractères ne sont pas supportés dans les URL ou ont un sens bien particulier, notamment ces ';' qui sont si présents dans un array serializé…
Mais une solution simple à cela est alors d'utiliser urlencode, qui encode ces caractères non supportés ou à sens particulier, pour le passage via URL. :)

Testons à nouveau !

<?php header("Location:autrepage.php?data=".urlencode($srzed)); // Une simple redirection, mais avec des données GET. exit; ?>

Et autrepage.php

<?php $arrayornot = unserialize(urldecode($_GET['datas'])); echo '<pre>'; print_r($arrayornot); echo '</pre>'; ?>

Magique, n'est-ce pas ?

L'enregistrement en base de données

Testons à présent l'insertion en BDD, sans doute le plus attractif pour beaucoup.
Le principe reste le même : on utilise serialize sur l'array et l'on enregistre. Mais il faut juste ajouter l'étape de protection des données. Certains utilisent mysql_real_escape_string, d'autres addslashes. Je pense qu'il s'agit de préférences, même si mysql_real_escape_stringdevrait être utilisé.

Ne négligez JAMAIS l'influence de ces petits caractères " et ' dans une requête SQL, de même que les antislashes. Ces caractères sont parmi les plus dangereux si non contrôlés. Et ce n'est pas parce que vous n'avez pas d'erreur que tout va bien…

Testons :

<?php mysql_query("INSERT INTO matable VALUES(NULL, 'serialize', '".mysql_real_escape_string($srzed)."')") or die(mysql_error()); ?>

Quand je dis que c'est magique... :)

Encore plus fort !Attendez, ce n'est pas fini !

Si je vous dis, à présent, que les arrays ne sont pas le seul type à être intéressant à serializer…

<?php class test { var $truc; var $machin; function test() // Constructeur peut aussi être appelé __construct en PHP 5. { $this->truc = mt_rand(1,99); $this->machin = array('truc'=>array(5,8,7),'chose'=>5,array('t','y','u','p')); } } $object = new test(); echo serialize($object); ?>

Citation : Affichage

O:4:"test":2:{s:4:"truc";i:37;s:6:"machin";a:3:{s:4:"truc";a:3:{i:0;i:5;i:1;i:8;i:2;i:7;}s:5:"chose";i:5;i:0;a:4:{i:0;s:1:"t";i:1;s:1:"y";i:2;s:1:"u";i:3;s:1:"p";}}}

Woh. Là, encore plus de possibilités, même si le tout reste identique. Le modèle semble très proche de celui des arrays : l'objet est délimité par des accolades.
Le nom de l'objet étant une chaîne de caractères, serialize précise le nombre de caractères de ce nom suivi du nombre d'éléments (propriétés) dans l'objet.
On peut donc utiliser serialize sur des objets.
Le nom de l'objet est conservé, ce qui permet, par exemple, de conserver des objets de diverses natures, comme un élément SimpleXML. :)
La transmission d'un objet par GET, ou son stockage en fichier ou en BDD est alors… réglé !

__sleep et __wakeup

Des méthodes magiques __sleep et __wakeup peuvent être définies spécialement pour serialize et unserialize. __sleep sera appelée automatiquement lors de serialize, et fera son office AVANT la linéarisation. __wakeup sera appelée automatiquement lors d'unserialize, et fera ses opérations APRÈS la délinéarisation.
Cela peut être très utile dans certains cas, comme pour une connexion à une base de données fermée par __sleep et relancée via __wakeup…

À noter que __sleep et __wakeup sont disponibles depuis PHP 4.
Je le précise, car on aurait tendance à penser, à cause de l'existence de __construct, que les méthodes magiques de classe datent de PHP 5. Ce n'est pas le cas.

Comportement de __sleep

Si __wakeup se comporte de manière relativement normale, il n'en est pas de même pour __sleep. Vous devez en effet systématiquement renvoyer un array contenant en valeurs les noms littéraux des variables.
Prenons cet exemple :

<?php class test { var $truc; function test() // Constructeur peut aussi être appelé __construct en PHP 5. { $this->truc = mt_rand(1,24); } function __sleep() { $this->truc *= 7; $this->truc -= 3; return array('truc'); // On renvoie un array contenant le nom littéral de la variable, c.-à-d. 'truc' ! } function __wakeup() { $this->truc += 3; $this->truc /= 7; } } $object = new test(); echo '<pre>'; print_r($object); // Sert à afficher de façon propre les propriétés d'un objet. echo '</pre>'; $mid = serialize($object); echo $mid; $last = unserialize($mid); echo '<pre>'; print_r($last); // Sert à afficher de façon propre les propriétés...

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Conservons nos variables avec serialize()

Prix sur demande