[spip-dev] Itérateurs

Hi,

avec http://core.spip.org/trac/spip/changeset/16670 je propose de
remplacer le CORPS des boucles par un appel à un itérateur générique
n'ayant pas la notion de SQL. Bien sûr dans un premier temps le seul
itérateur connu est de type SQL. Mais en évacuant la notion SQL dans
la classe d'itération, on peut désormais imaginer un itérateur JSON ou
FICHIERS ou ... TABLEAU PHP.

Reste à voir quels critères permettent d'initialiser ces itérateurs proprement.

A noter : PHP offre aussi une notion d'itérateur générique
http://fr.php.net/manual/en/class.iterator.php

-- Fil

11/12/10, Fil:

avec http://core.spip.org/trac/spip/changeset/16670 je propose de
remplacer le CORPS des boucles par un appel à un itérateur générique
n'ayant pas la notion de SQL.

Super idée. (bon je connais pas le fonctionnement du compilo et tout
ça, mais vu comme ça de l'extérieur je trouve ça chouette).

A noter : PHP offre aussi une notion d'itérateur générique
PHP: Iterator - Manual

Du coup, y a-t-il une raison pour ne pas avoir mis de
"implements Iterator" après la définition de la classe Iter ? A priori
tes fonctions se mappent assez bien :

  Iterator::current = Iter::select
  Iterator::key = un compteur interne incrémenté à chaque pas
                  (#COMPTEUR_BOUCLE)
  Iterator::next = Iter::next
  Iterator::rewind = Iter::seek(0)
  Iterator::valid() = Iter::ok

Bien sûr dans un premier temps le seul itérateur connu est de type
SQL. Mais en évacuant la notion SQL dans la classe d'itération, on
peut désormais imaginer un itérateur JSON ou FICHIERS ou ... TABLEAU
PHP.

Bonne idée. Du coup on pourrait avoir un système d'héritage. Par
exemple :

  IterateurSPIP implements Iterator

    Ça définit les fonctions d'Iterator (current, key, next, rewind,
    valid), plus celles dont on a besoin pour SPIP le cas échéant,
    genre free ou count qui sont pratiques.

  IterateurSQL implements IterateurSPIP
  IterateurJSON implements IterateurSPIP
  IterateurArray implements IterateurSPIP
  IterateurXML implements IterateurSPIP

(au lieu de Iterateur on peut dire Boucle)

Ainsi, SPIP utiliserait IterateurSPIP (ou BoucleSPIP), et un plugin
peut définir son propre IterateurPatate (BouclePatate) qui implémente
les fonctions définies dans IterateurSPIP, un peu comme on fait déjà
sur l'interface d'abstraction SQL.

Petite question peut-être inutile, mais que c'est bien de poser au cas
où : a priori, le type d'objet renvoyé par un Iter est actuellement un
tableau (ayant pour clés et valeurs celles définies par sql_fetch). Si
on définit une interface d'abstraction pour les itérateurs SPIP, il
faudra voir si ça convient tel quel comme conteneur d'information.

Du coup, y a-t-il une raison pour ne pas avoir mis de
« implements Iterator » après la définition de la classe Iter ? A priori
tes fonctions se mappent assez bien :

je préfère ne pas dépendre d’un truc php que je ne connais pas bien (notamment le risque sur les numéros de version de PHP), mais en gros c’est l’idée.

Pour donner un exemple j’ai fait une boucle POUR avec cette notion, le code est assez propre, même si on est obligé de ruser un peu pour défaire le sql_quote (il y a sans doute plus intelligent à faire de ce point de vue).

Petite question peut-être inutile, mais que c’est bien de poser au cas
où : a priori, le type d’objet renvoyé par un Iter est actuellement un
tableau (ayant pour clés et valeurs celles définies par sql_fetch). Si
on définit une interface d’abstraction pour les itérateurs SPIP, il
faudra voir si ça convient tel quel comme conteneur d’information.

oui, là ça colle à l’existant, mais il y a peut-être de nouvelles choses qui vont apparaître.

– Fil

Je viens d'ajouter deux sortes d'itérateurs : ENUM et DATA

   Boucle DATA:

Hello,
je suis pas sur de bien comprendre (ENUM){1,8}
S'agit-il de parcourir la liste de données (1,8)
ou l'intervalle de 1 à 8 : 1,2,3,4,5,6,7,8

ENUM me fait plus penser à une liste de valeur énumérées explicitement.

Un intervalle serait plus obtenu par un RANGE, auquel il faudrait aussi une valeur de pas possible
Peut être tout simplement INTERVALLE alors :
(INTERVALLE){1,8} => 1,2,3,4,5,6,7,8
(INTERVALLE){1,8,2} => 1,3,5,7
(INTERVALLE){8,1,-2} => 8,6,4,2

Tout ça est super, on va pouvoir réécrire un modèle de pagination carrément moins gourmand (il y a le proto dans bonux)
et s'en servir aussi pour les squelettes du prive.

Cédric

je suis pas sur de bien comprendre (ENUM){1,8}
S'agit-il de parcourir la liste de données (1,8)
ou l'intervalle de 1 à 8 : 1,2,3,4,5,6,7,8

en l'occurrence c'est l'intervalle

ENUM me fait plus penser à une liste de valeur énumérées explicitement.

l'idée d'ENUM c'est de faire un truc qui s'incrémente. si c'est pas
clair il faut en changer le nom, INTERVALLE me convient même si un peu
trop long (car on va l'utiliser partout)

Sinon la liste de valeurs explicites, ce serait plutôt DATA
{datasource #ARRAY{1,2,3,4},table} -- mais j déteste #ARRAY avec sa
syntaxe cle,valeur,cle,valeur...

alors peut-être
DATA {datasource "1,2,3,4", list} (mais argggh il y a un guillemet de
trop là !)
... bref à réfléchir encore

Un intervalle serait plus obtenu par un RANGE, auquel il faudrait aussi une
valeur de pas possible

Le pas me paraît inutile, dès lors qu'on a |mult ; et ça compliquerait
l'analyse. {1,8} se base sur "limit" exactement comme le {1,8} de
l'itérateur SQL

Tout ça est super, on va pouvoir réécrire un modèle de pagination carrément
moins gourmand (il y a le proto dans bonux)

oui entre autres

et s'en servir aussi pour les squelettes du prive.

:slight_smile:

-- Fil

12/12/10, Fil:

l'idée d'ENUM c'est de faire un truc qui s'incrémente. si c'est pas
clair il faut en changer le nom, INTERVALLE me convient même si un peu
trop long (car on va l'utiliser partout)

SEQ ? En shell par exemple, seq 1 8 renvoie 1 2 3 4 5 6 7 8.
Bon ça vient de l'anglais "sequence" qui veut dire "suite", mais bon
même en français SEQ ça se comprend (séquentiel, tout ça).

En fait je pense pas que ce type d'iterateur soit necessaire

En python par exemple, il n'existe pas, et on ne peut iterer que sur des tableaux.
L'equivalent du for se fait donc par une fonction range qui construit une sequence entre 2 nombres.
Ce serait chez nous quelque chose comme
#RANGE{1,8}
#INTERVALLE{1,8}
#SEQUENCE{1,8}

reutilisable dans d'autres contextes.

Cédric

En fait, je ne comprends pas le risque. Je suppose qu'il est pourtant plus performant d'utiliser la bibliothèque PHP fournie pour faire ça. Ce sera aussi moins de chose à apprendre pour les développeurs...

Matthieu.

En fait je pense pas que ce type d'iterateur (ENUM) soit necessaire
En python par exemple, il n'existe pas, et on ne peut iterer que sur des
tableaux.
L'equivalent du for se fait donc par une fonction range qui construit une
sequence entre 2 nombres.
Ce serait chez nous quelque chose comme
#RANGE{1,8}
#INTERVALLE{1,8}
#SEQUENCE{1,8}
reutilisable dans d'autres contextes.

avec ça tu es obligé de donner une borne sup à ton intervalle, ce qui
me paraît contraire à la notion d'itérateur.

Cf. <BOUCLE_a(ENUM){pagination 10} > qui ne donne pas de borne sup ;
(même si j'ai mis 1000000 en dur dans le code, mais c'est uniquement
histoire de répondre à #TOTAL_BOUCLE)

On peut aussi imaginer un itérateur qui fait un calcul (complexe) à
chaque ->next(), et ne sait pas avant d'avoir tout calculé quand il va
s'arrêter

-- Fil

Du coup, y a-t-il une raison pour ne pas avoir mis de
"implements Iterator" après la définition de la classe Iter ? A priori
tes fonctions se mappent assez bien :

je préfère ne pas dépendre d'un truc php que je ne connais pas bien
(notamment le risque sur les numéros de version de PHP), mais en gros
c'est l'idée.

En fait, je ne comprends pas le risque.

Pourquoi je ne l'ai pas fait :
1. Je ne sais pas à partir de quelle version de PHP cette class est dispo.
2. De plus je ne vois pas ce qu'elle pourrait nous apporter.

Si tu as la réponse à ces deux notions gogogo :slight_smile:

aussi moins de chose à apprendre pour les développeurs...

oui, bon argument

-- Fil

http://fr.php.net/manual/fr/iterator.next.php

PHP 5.1

2. De plus je ne vois pas ce qu'elle pourrait nous apporter.

OK je viens de réaliser un intérêt potentiel : si quelqu'un quelque
part a fait (par exemple) un webservice et fournit une class Iterator
pour l'exploiter, le branchement de cette class sous SPIP sera
simplifié.

-- Fil

On avait d'ailleurs évoqué que ce serait la version minimale requise pour la prochaine version majeure de SPIP

Cédric

PHP: Iterator::next - Manual
PHP 5.1

On avait d'ailleurs évoqué que ce serait la version minimale requise pour la
prochaine version majeure de SPIP

Oui, pas de problème de ce point de vue. Une fois les itérateurs
stabilisés, on pourra d'ailleurs les backporter en 2.1 via un plugin
:slight_smile:

-- Fil