Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

UTILISER LES ITÉRATEURS EN PHP5


Information sur le tutorial

Catégorie :Class et Objet ( POO ) Date de création : 29/03/2007 17:26:57 Vu : 7 211 fois

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

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (9)
Ajouter un commentaire et/ou une note

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 !! :)


signaler à un administrateur
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.

signaler à un administrateur
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

signaler à un administrateur
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;
}

signaler à un administrateur
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 :)

signaler à un administrateur
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 !

signaler à un administrateur
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 !

signaler à un administrateur
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 ...)

signaler à un administrateur
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é.

signaler à un administrateur
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!

Ajouter un commentaire



Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



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
Temps d'éxécution de la page : 0,016 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.