begin process at 2010 02 09 22:21:30
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

Class et Objet ( POO )

 > UTILISER LES ITÉRATEURS EN PHP5

UTILISER LES ITÉRATEURS EN PHP5


 Information sur le tutoriel

Note :
10 / 10 - par 2 personnes
10,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

 Description

Histoire de voir un petit peu comment ca fonctionne.

Tutorial

Les itérateurs... ouh la ! Un grand sujet de PHP5 !
Il faut savoir que les itérateurs, c'est un gros morceaux de la SPL fournit par PHP5 (compilé et activé par défaut), et qu'il n'est pas si facile que ca à comprendre du premier coup.

Si je fais ce petit tuto, c'est pour que vous compreniez dans son ensemble ce que sont les itérateurs (on poussera plus loin éventuellement plus tard ^^).

D'abord comment ca marche ?
Les itérateurs fonctionnent sur des classes, et seulement des classes ! Les itérateurs sont des interfaces qui fournissent des méthodes publics pour accéder aux instances de classes.

L'itérateur "standard" nécéssite 5 méthodes publics ( key(), valid(), next(), rewind(), current() ).
Voici ce que cela donne en réel :
<?php
 class x implements iterator {
  private $output;
  private $query;
  private $key;

  public function __construct($query) {
   $this->query = $query;
  }
 
 public function key() {
  return $this->key;
 }

 public function valid() {
 return isset($this->output);
 }

 public function next() {
 $this->output = mysql_fetch_array($this->query);
 $this->key++;
 }

 public function rewind() {
 mysql_seek(0); // Je crois...
 $this->key = 0;
 }

 public function current() {
 return $this->output;
 }
}
?>
Voici la classe. Voyons maintenant comment cela peut fonctionner :
<?php
 $Iterate = new x( mysql_query('SELECT * FROM news') );
 foreach ( $Iterate as $key->$news ) {
   echo $news['id'];
   echo $news['titre'];
   echo $news['contenu']; // etc...
 }
?>

Et voila, c'est aussi simple ! Alors vous allez me demandez pourquoi utiliser les itérateurs alors que je peux utiliser un simple :
while ( $data = mysql_fetch_array(...) ) {
 //
}
?

Imaginons que vous souhaitez, en plus de developper un système de news, un système de commentaires, de gestions de liens, de téléchargements, de threads pour un forum, de topics, de replys etc....
Déja, nous partons dans le principe d'une gestion objet.
Cela signifie, dans un premier temps, que mes classes qui vont gérer les modules ne sont pas censé savoir d'où proviennent les données ! C'est la que ca devient intéressant.
Je peux récupérer mes news via SQL, mais aussi via XML ou via fichiers simples... ou RSS bref, le choix est étendu !
Vous vous voyez copier 40 fois le code avec des if() ??? Pas moi.

La où les itérateurs prennent tous leurs sens, c'est qu'on peut y faire passer ce que l'on veut dedand et en faire ressortir également ce que l'on veut.
Un exemple avec un niveau d'abstraction plus élevé :

<?php
 class x implements iterator {
  private $output;
  private $resource;
  private $key;
  private $class_input;
  private $class_output;

  public function __construct($resource, $nom_de_la_classe_où_les_donnees_proviennent, $nom_de_la_classe_où_les_donnees_vont_sortir) {
   $this->resource = $resource;
   $this->class_input = new $nom_de_la_classe_où_les_donnees_proviennent;
   $this->class_output = $nom_de_la_classe_où_les_donnees_vont_sortir;
  }
 
 public function key() {
  return $this->key;
 }

 public function valid() {
 return isset($this->output);
 }

 public function next() {
 $this->output = new $this->class_output( $this->class_input('Next_Element', $resource) ); // C'est mal écrit mais je ne peux pas faire autrement, disons que je dit
// que je veux faire passer la méthode qui va me permettre de passer à l'élément suivant de ma ressource et renvoyer le résultat de cette méthode dans ma classe d'output.
 $this->key++;
 }

 public function rewind() {
 $this->class_input('Rewind_Elements');
 $this->key = 0;
 }

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

Je prend l'exemple d'une classe SQL :
<?php
 class sql {
  // je passe la classe en détail ...
static public function Next_Element($query) {
 return mysql_fetch_array($query);
}
 }
?>

Et maintenant, si je veux récupérer des news :
<?php
 $sql = new mysql;
 $IterateMe = new x ( $sql->query('SELECT * FROM news'), $sql, 'news');
 foreach ( $IterateMe as $key=>$news) {
      // $news est une instance de la classe 'news' comme je l'ai demandé !!
 }

// Si je veux faire pareil avec des liens :
$IterateMe = new x ($sql->query('SELECT * FROM links'), $sql, 'liens');
 foreach ( $IterateMe as $key=>$link) {
  // $link est une instance de la classe 'liens' comme je l'ai aussi demandé :)
 }

?>

Et je peux aussi utiliser XML à la place, il me suffit de remplacer la requète SQL par une requète Xpath, d'envoyer la classe qui permet d'utiliser la méthode 'Next_Element' pour XML et ca marche aussi bien :)

L'itérateur permet ici de faire du bouclage quelque soit l'entrée et quelque soit la sortie.
On peut l'utiliser avec le principe de reflection pour ajouter un peu de dynamisme et de lisibilité d'écriture...


Mais l'itérateur ne s'arrète pas la, il existe d'autres formules d'itérations possible ( des dossiers, des itérateurs d'itérateurs ... des agrégations d'itérateurs...), bref tout devient possible !
En tout cas, après avoir lu ce tuto, j'espère ne plus voir quelque chose comme :
<?php
class mysql {
 //
 public function GetAllNews() {
  $array = array();
   while($data = mysql_fetch_array($this->query) ) {
           $array[] = $data;
   }
  return $array;
 }

}

$sql = new mysql;
$allnews = $sql->GetAllNews();
 foreach ( $allnews as $key=>$news ) {
   //
 }
?>

C'est ce que je vois bien trop souvent... parcourir deux fois ses données ... une belle perte de temps :) Maintenant avec les itérateurs, tout devient possible en une seule fois !! :)


Commentaires

Commentaire de craso le 18/05/2007 14:59:59

bravo, tout s'eclaire... grace a toi!
merci, je vais l'utiliser tout de suite de go dans mon projet.

Commentaire de craso le 18/05/2007 15:18:53

public function next() {
$this->output = new $this->class_output( $this->class_input('Next_Element', $resource) );

=>il faut certainement remplacer $resource par $this->ressource

Commentaire de craso le 22/05/2007 02:04:30

pour la classe "mysql", la premiere, il faut mettre quelque chose du genre :
public function valid()
{
return false !== $this->output;
}

Commentaire de FhX le 22/05/2007 20:13:16

"=>il faut certainement remplacer $resource par $this->ressource"
En effet :)

"pour la classe "mysql", la premiere, il faut mettre quelque chose du genre :"
isset() marche très bien aussi :)

Commentaire de codefalse le 25/05/2007 10:28:37 administrateur CS

Yok!
Ya un petit truc qui me chagrine :
$sql = new mysql;
$IterateMe = new x ( $sql->query('SELECT * FROM news'), $sql, 'news');

Si je vais voir le constructeur de la classe x, j'ai :
public function __construct($resource, $nom_de_la_classe_où_les_donnees_proviennent, $nom_de_la_classe_où_les_donnees_vont_sortir) {
   $this->resource = $resource;
   $this->class_input = new $nom_de_la_classe_où_les_donnees_proviennent;
   $this->class_output = $nom_de_la_classe_où_les_donnees_vont_sortir;
  }

Donc le premier paramèetre, c'est la ressource (donc ici la requete sql),
mais le deuxieme et le troisieme parametre me perturbe :
le deuxieme est l'instance de la classe sql ($sql) et dans le constructeur tu refait new $sql,
et pour le troisieme parametre 'news', tu fait juste $this->class_output = $nom_de_la_classe_où_les_donnees_vont_sortir; pas de new $nom_de_la_classe_où_les_donnees_vont_sortir.

Est-ce normal ? si oui pourriez vous m'expliquer un peu plus ?, je vous en serai bien reconnaissant !

Commentaire de FhX le 06/06/2007 19:46:45

jrépond vite fait :)

"Donc le premier paramèetre, c'est la ressource (donc ici la requete sql), " Exact.
"le deuxieme est l'instance de la classe sql ($sql) et dans le constructeur tu refait new $sql"
Dans cet exemple, c'est juste le nom de la classe SQL. Voila pourquoi j'y fais un new, pour l'instancier. (dans ma nouvelle version, j'utilise la reflection ^^)

"et pour le troisieme parametre 'news', tu fait juste $this->class_output = $nom_de_la_classe_où_les_donnees_vont_sortir; pas de new"
=> $this->output = new $this->class_output( $this->class_input('Next_Element', $resource) ); //

Y'a un new() pourtant !

Il suffit de faire passer juste le nom des classes : le nom de la classe SQL et le nom de la classe que tu veux recevoir (news, download, membre, user, etc...).

C'est un exemple parmis tant d'autre !

Commentaire de craso le 14/06/2007 15:46:51

FHX: et tu saurais expliquer comment utiliser FilterIterator, en vite fait, car je nage là (peut être que j'ai trop mangé aussi ...)

Commentaire de craso le 15/06/2007 19:51:16

=>"pour la classe "mysql", la premiere, il faut mettre quelque chose du genre :"
isset() marche très bien aussi :)
bizarre chez moi, la classe "rembobine" puis s'arrete, $this->output n'existe pas apres avoir rembobiner, ou un element de comprehension m'a echappé.

Commentaire de craso le 15/06/2007 19:53:00

=> http://www.phpro.org/index.php?p=tutorials&kbid=1 , je vais y passé au moins la journée a lire, comprendre tout ce qui est dit là-dedans!

Commentaire de devcphp12 le 14/10/2009 19:04:35

Voici la classe. Voyons maintenant comment cela peut fonctionner :
<?php
$Iterate = new x( mysql_query('SELECT * FROM news') );
foreach ( $Iterate as $key->$news ) {
   echo $news['id'];
   echo $news['titre'];
   echo $news['contenu']; // etc...
}
?>

prmeier exemple, si j'ai bien tout suivi la clef de tableau ne sert à rien donc on peut directement faire un  

foreach ($Iterate as $news)
{ ...
}
Est ce bon ?

Commentaire de devcphp12 le 14/10/2009 21:24:46

On pourrait meme voir plus large en implementant la connexion à la base de données directement dans la classe ainsi on ne passerait que la requete sql au constructeur.Qu'en pensez vous?

J'ai fait mes premiers tests et rien en s'affiche!! Dois on etre obligatoirement en php5.3 pour pouvoir les utiliser?

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,172 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales