Suite de ma série consacrée aux modes de récupération de PDO, voici les modes qui permettent de travailler avec des objets.
FETCH_OBJ
Le tableau retourné contient les résultats sous forme d’instances de stdClass, contenant les valeurs des colonnes comme des variables publiques. Ce mode ne permet pas de récupérer plusieurs colonnes avec le même nom (voir FETCH_ASSOC).
Exemple :
Array
(
[0] => stdClass Object
(
[id] => 1
[login] => toto
)
[1] => stdClass Object
(
[id] => 2
[login] => titi
)
)
Par rapport à FETCH_BOTH :
- Temps de récupération : +7,6% (à noter qu’avec
while + fetch, ça passe à +30%) - Taille du résultat : -15%
Cette méthode est plus lente que la méthode par défaut (qui est déjà particulièrement lente), et honnetement, je ne vois pas l’avantage d’un objet par rapport à un tableau associatif renvoyé par FETCH_ASSOC…
FETCH_CLASS
Ce mode est équivalent à FETCH_OBJ sauf qu’il permet d’utiliser une classe personnalisée pour stocker les résultats. Ce mode ne permet pas de récupérer plusieurs colonnes avec le même nom (voir FETCH_ASSOC).
Ce mode nécessite de passer, en plus du mode, des paramètres supplémentaires. D’après la documentation, il faudrait utiliser la fonction setFetchMode pour passer ces paramètres (ou directement au moment de faire query), mais en pratique, fetchAll les accepte aussi (alors qu’ils ne sont censés exister)… Par contre, fetch ne les accepte pas.
Le deuxième paramètre est donc le nom d’une classe. Si la classe contient déjà des variables correspondantes aux colonnes, PDO les rempli et se fiche pas mal de leur visibilité. Sinon, PDO crée les variables avec une visibilité publique. Un troisième paramètre (optionnel) permet de passer des paramètres au constructeur de la classe. A noter que quand le constructeur est appellé, les variables internes ont déjà une valeur (voir FETCH_PROPS_LATE dans le dernier article de cette série si ce comportement pose un problème).
Si la classe n’existe pas, le résultat est un tableau identique à celui obtenu avec FETCH_BOTH (si un autre mode par défaut est défini, il n’est pas pris en compte).
Exemple :
class MyClass
{
function __construct()
{
var_dump(func_get_args()); // affiche 'foo' et 'bar'
var_dump($this->id, $this->login); // affiche l'id et le login
}
}
$results = $dbh->query($sql);
$results->fetchAll(PDO::FETCH_CLASS, 'MyClass', array('foo', 'bar'));
Array
(
[0] => MyClass Object
(
[id] => 1
[login] => toto
)
[1] => MyClass Object
(
[id] => 2
[login] => titi
)
)
Les performances dépendent évidemment de la taille de la classe : plus il y a d’infos dedans, pire c’est. Avec une classe entièrement vide (c’est-à-dire avec meilleures performances possibles), on obtient, par rapport à FETCH_BOTH :
- Temps de récupération : +6% (à noter qu’avec
while + fetch, ça passe à +32%) - Taille du résultat : dépend de la taille de la classe
En déclarant un constructeur (même vide), les performances se dégradent énormement parceque le constructeur est appellé à chaque ligne de résultat :
- Temps de récupération : +55% (avec
while + fetch, ça descend à +36%) - Taille du résultat : dépend de la taille de la classe
Pour faire court : les performances sont catastrophiques par rapport aux modes classiques. Il est peut-être possible d’utiliser ce mode pour créer un petit ORM, mais pour l’instant je ne vois pas bien l’utilité.
FETCH_INTO
Ce mode permet de récupérer les données *dans* une instance de classe déjà existante…
Pour utiliser ce mode, il faut passer en paramètre la variable qui contient l’instance à modifier. Comme pour FETCH_CLASS, d’après la documentation il faut utiliser la fonction setFetchMode (ou directement query) pour passer ce paramètre. Et cette fois, curieusement, ni fetchAll ni fetch ne les accepte (avec fetchAll on obtient l’erreur plutôt originale SQLSTATE[HY000]: General error: Extraneous additional parameters
).
La seule manière est donc d’utiliser :
class MyClass { }
$toto = new MyClass();
$results->setFechMode(PDO::FETCH_INTO, $toto);
// fetch
Attention, contrairement à FETCH_CLASS, si vous déclarez dans la classe les variables correspondant au nom des colonnes en protected ou private, PDO va retourner une erreur : Fatal error: Cannot access protected (ou private) property MyClass::$id
.
Avec fetchAll, on obtient un tableau contenant exactement la même instance de classe autant de fois qu’il y a de lignes dans la réponse… L’instance contient uniquement les valeurs de la dernière ligne. C’est donc totalement inexploitable. Exemple :
Array
(
[0] => MyClass Object
(
[id] => 2
[login] => toto
)
[1] => MyClass Object
(
[id] => 2
[login] => toto
)
)
Si on utilise fetch dans une boucle while, fetch retourne à chaque étape une référence vers l’instance. Exemple :
while ( $r = $results->fetch() ) var_dump($r == $toto); // affiche true
On peut donc utiliser :
while ( $results->fetch() ) print_r($toto);
MyClass Object ( [id] => 1 [login] => toto ) MyClass Object ( [id] => 2 [login] => titi )
J’ai estimé les performances avec fetchAll afin de pouvoir comparer les résultats, mais il est important de noter qu’avec ce mode fetchAll ne sert à rien… Par rapport à FETCH_BOTH, on obtient :
- Temps de récupération : -3,5% (avec
while + fetchça descend à -9%) - Taille du résultat : dépend de la taille de la classe
Le temps de récupération est plus court que FETCH_CLASS ou FETCH_OBJ car l’objet est déjà instancié. Mais, même si les performances sont correctes, pour l’instant je n’ai pas encore trouvé d’utilisation concrète pour ce mode.
A suivre : les modes spéciaux et les modes modificateurs.
[...] d’articles si vous voulez connaître toutes les possibilités : les fetch modes de PDO, les fetch modes de PDO orientés objet, les fetch modes spéciaux de PDO et les fetchs modes modificateurs de PDO. Tags: base de données, [...]
Posted by Tilàcica » Blog Archive » 10 bonnes raisons d’utiliser PDO (PHP Data Object) on March 9th, 2009.