Auteur: Ludovic PATEY

Publié le 7 avril 2008

Modifié le: 7 avril 2008

Page d'accueil

Introduction à Standard PHP Library

Vous êtes ici : Accueil / Articles / Formations en PHP

Qu’est-ce que la SPL ?

La SPL est une libraire de fonctions PHP incluse par défaut dans PHP5. Elle permet de résoudre les problèmes parmi les plus courants. Cette librairie se focalise sur tout sur le contrôle des itérations. Bien que très peu connue des développeurs, elle a tout de suite été remarquée par les créateurs de frameworks qui l’ont utilisé notamment pour utiliser du avoir recours au lazy loading ( chargement à la demande ).

L’interface Countable

Cette interface permet de redéfinir la valeur retournée par la fonction count() appelée sur un objet. Il faut pour cela écrire la méthode count() dans la classe :

<?php
class MaCollection implements Countable {

       private $array ;

       // Redéfinition de la methode count()
       public function count() {
               return count($this->array ) ;
       }

}
?>

Il est alors possible d’appeler la méthode count() sur l’objet

<?php
$collection = new MaCollection();

// Appelle la méthode count() de MaCollection
echo count( $collection );
?>

L’interface Iterator

Cette interface va permettre de redéfinir les valeurs retournées lors du recours à la structure foreach. Il va falloir réimplémenter un certain nombre de méthodes, ce qui peut s’avérer assez lourd. Cependant, nous verrons ensuite quelques classes permettant de ne redéfinir que les méthodes voulues :

- current()

Cette méthode retourne la valeur courante. Elle sera appelée dans un foreach ou un each()

- key()

Retourne la clé de la position courante. Cette méthode est appelée avec la syntaxe foreach( $o as $cle => $value ).

- next()

Cette méthode est appelée pour déplacer la position courante vers l’avant.

- rewind()

Cette méthode est appelée au tout début de l’instruction foreach est sert à repositionner le pointeur au début du tableau.

- valid()

Retourne un booléen pour préciser si la position courante du pointeur est valide ou non.

- Attention aux amalgames

Certaines méthodes présentées précédemment ont des similarités de nom avec quelques fonctions PHP de manipulation de tableau, comme key(), next()... Les méthodes de l’interface Iterator ne sont pas appelées lors de l’utilisation de ces fonctions.

-  Exemple

<?php
class Test implements Iterator {

       private $array = array( 'k1' => 'v1', 'k2' => 'v2');

       public function current() {
               return current($this->array);
       }

       public function key() {
               return key($this->array);
       }

       public function next() {
               return next($this->array);
       }

       public function rewind() {
               reset($this->array);
       }

       public function valid() {
               return current( $this->array );
       }
}


$t = new Test();

foreach( $t as $k => $v ) {
       echo "Cle: $k Valeur : $v\n";
}
?>

L’interface IteratorAggregate

Bien que très utile, l’interface Iterator est un peu lourde à utiliser si vous n’avez qu’un simple tableau à manipuler. L’interface IteratorAggregate permet de ne proposer qu’une méthode : getIterator() appelée au moment de l’instruction foreach, et permet d’utiliser une classe déjà implémentée comme ArrayIterator. Ainsi, la classe suivante est l’équivalent de la précédente :

<?php
class Test implements IteratorAggregate {

       private $array = array( 'k1' => 'v1', 'k2' => 'v2');

       public function getIterator() {
               return new ArrayIterator( $this->array );
       }
}


$t = new Test();

foreach( $t as $k => $v ) {
       echo "Cle: $k Valeur : $v\n";
}
?>

L’interface ArrayAccess

Nous avons vu comment redéfinir les actions lors de l’utilisation d’une structure itérative. Il manque une syntaxe pour reproduire un tableau à partir d’une classe : la syntaxe [] pour accéder aux éléments par leur index. Ce manque est comblé par l’interface ArrayAccess :

- bool offsetExists( mixed )

Cette méthode précise si la clé utilisée existe. Retourne un booléen. Elle est appelée lors de l’utilisation de la fonction isset().

-  mixed offsetGet( mixed )

Retourne la valeur correspondant à la clé passée en paramètre. Cette méthode est appelée par la syntaxe []

-  mixed offsetSet( mixed, mixed )

Définit une valeur correspondant à la clé passée en premier argument, et retourne la valeur. Cette méthode est appelée avec l’opérateur d’affectation et la syntaxe [].

-  void offsetUnset( mixed )

Supprime l’association clé-valeur dont la clé est passée en paramètres. Cette méthode est appelée avec la fonction unset().

-  Exemple :

<?php
class Test implements ArrayAccess {

       private $array = array( 'k1' => 'v1', 'k2' => 'v2');

       public function offsetExists( $k ) {
               echo "ok";
               return isset( $this->array[ $k ] );
       }

       public function offsetGet( $k ) {
               return $this->array[ $k ];
       }

       public function offsetSet( $k, $v ) {
               $this->array[ $k ] = $v;
       }

       public function offsetUnset( $k ) {
               unset( $this->array[ $k ] );
       }
}


$t = new Test();

if( isset( $t['k1'] ) ) {

       echo $t['k1'];

       unset( $t['k1'] );
}
?>

La classe ArrayObject

Cette classe se comporte exactement comme un tableau, à la différence près que c’est un objet. L’avantage ? les tableaux ont des passages par valeur par défaut alors qu’un objet n’est passé que par référence. L’opérateur d’égalité réagira différemment en fonction du fait que cela soit un tableau ou un objet.

<?php
$a = new ArrayObject( array( 'cle' => 'valeur' ) );
$b = new ArrayObject( array( 'cle' => 'valeur' ) );

// Affiche valeur
echo $a['cle'];

// Vaut faux
echo $a === $b;
?>

Spécifier plusieurs fonctions autoload()

- La fonction __autoload()

Il existe depuis PHP 5 une fonction spéciale, __autoload() appelée lors d’une instanciation si une classe n’a pas encore été définie. Elle permet de charger la classe « à la volée » en incluant le fichier contenant le déclaration de la classe. Sa définition est souvent la suivante :

<?php
function __autoload( $className ) {

       require_once $className . '.class.php';
}

// Va essayer d?inclure le fichier MaClasse.class.php
// Pour charger la classe à la volée
$maClasse = new MaClasse();
?>

- Les limites de cette fonction

Cette fonction trouve ses limites dans la programmation modulaire : les répertoires contenant les classes sont souvent dans des dossiers différents suivant les modules, et la définition de la fonction __autoload() peut entraîner des conflits entre ceux-ci. Il devient donc nécessaire de pouvoir spécifier plusieurs fonctions __autoload() pour que chaque module puisse utiliser la fonctionnalité.

- La fonction spl_autoload_register()

SPL propose une fonction nommée spl_autoload_register() dont le prototype est le suivant :

<?php
bool spl_autoload_register ([ mixed $autoload_function ] )
?>

Comme le montre son prototype, cette fonction permet d’ajouter des fonctions qui seront appelées lors du chargement à la volée. Si la classe n’est pas trouvée par une fonction, la suivante est évaluée. Cette fonction n’exclus évidemment pas les conflits de nom entre les classes. Il est pour cela conseillé de s’astreindre à un nommage très strict en préfixant ses classes par le nom du module. Ce problème tendra à disparaître avec les espaces de nommage introduits en PHP 6.

SPL fournit d’autres fonctions, notamment pour lister les fonctions de chargement et pour en ôter.

Implémenter du lazy loading avec SPL

Un des principaux avantages des itérateurs réside dans l’utilisation du lazy loading. Prenons un exemple concret : Nous voulons développer une classe pour interagir avec une base de données. Les transferts sont lents et il est préférable d’éviter les requêtes inutiles. Il devient alors utile d’avoir recours aux itérateurs pour n’effectuer la requête que si un foreach est exécuté. C’est notamment le choix de la librairie PHP:DBO.

Pour implémenter du lazy loading, nous avons besoin de d’un getter, et d’une variable pour stocker la donnée une fois chargée afin d’éviter de la recharger la fois suivante. Pour plus de clarté, nous avons rajouté une méthode privée de chargement de données, et qui ne doit être appelée qu’une fois.

<?php
class LazyLoading {


       private function loadData() {
               // Recuperation des données
       }

       public function getData() {

               if( !$this->data ) {
                       $this->data = $this->loadData();
               }

               return $this->data;

       }

}
?>

Le fait que la méthode loadData() soit en private empêche le développeur d’y avoir accès en dehors de la classe. Nous voyons clairement que si celui-ci ne fait pas appel à la méthode getData(), les données ne seront jamais importées.

Pour accéder aux données, la syntaxe sera la suivante :

<?php
$test = new LazyLoading();

foreach( $test->getData() as $cle => $valeur ) {

       // Utilisation des données
       echo $valeur;
}
?>

Cependant, cette méthode de lazy loading nous oblige à appeler la méthode getData(). Grâce à SPL, ce n’est plus nécessaire :

<?php
class LazyLoading implements IteratorAggregate {


       private function loadData() {
               // Recuperation des données
       }

       public function getIterator() {

               if( !$this->data ) {
                       $this->data = $this->loadData();
               }

               return new ArrayIterator( $this->data );

       }

}
?>

Pour accéder aux données, la syntaxe sera la suivante :

<?php
$test = new LazyLoading();

foreach( $test as $cle => $valeur ) {

       // Utilisation des données
}
?>

Liens

http://www.phpriot.com/articles/oop-with-spl-php-5/1

http://www.php.net/ helly/php/ext/spl/

http://fr.php.net/spl

Commentaires

Auteur :

Message :