Précédent   Forum du club des développeurs et IT Pro > PHP > Langage > Contribuez
Contribuez Proposez vos articles, cours, tutoriels, FAQ, sources, etc. pour PHP
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 30/03/2011, 13h06   #1
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
Par défaut PDOStatemnt & Iterator

Bonjour à tous.

Je vous propose la classe PDOStatementIterator. J'ai été amené à créer cette classe pour faciliter l'usage des Iterators avec les PDOStatement car bien que ces derniers implémentent l'interface Traversable, il n'est pas possible de l'utiliser comme un Iterator (du moins pas directement). Il est vrai que l'usage de IteratorIterator nous permet de contourner ce problème, mais on aimerai grandement pouvoir se positionner dans le PDOStatement (SeekableIterator) et compter le nombre de lignes retournées (Countable), c'est là que PDOStatement entre en scène.

Voici le code source de la classe:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
class PDOStatementIterator extends IteratorIterator implements SeekableIterator, Countable {
 
    protected $_statement;
 
    protected $_count;
 
    public function __construct (PDOStatement $statement) {
        parent::__construct($this->_statement = $statement);
    }
 
    public function seek ($position) {
        if ($position > $this->count() || $position < $this->key())
            throw new OutOfBoundsException("Cannot seek to $position");
 
        for ($i = $this->key(); $i < $position; $i++)
            $this->next();
    }
 
    public function count () {
        if (!isset($this->_count))
		    return $this->_count = $this->_statement->rowCount();
	    return $this->_count;
    }
}
Cette classe est ni plus ni moins qu'un IteratorIterator seekable et coutable... On conserve une référence sur le PDOStatement à cet effet.
L'usage de cette classe est indépendant du fetch_mode choisi dans le PDOStatement, ce qui la rends bien pratique pour récupérer des collections en LazyLoading.
Exemple:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
class User { 
  protected $_data;
 
  public function __get ($key) {
    return isset($this->_data[$key]) ? $this->_data[$key] : null;
  }
 
  public function __set ($key, $value) {
	$this->_data[$key] = $value;
  }
}
 
// ...
 
$user = new User;
 
$stmt = $pdo->prepare('SELECT * FROM `users`');
$stmt->setFetchMode(PDO::FETCH_INTO, $user);
$stmt->execute();
 
$it = new PDOStatementIterator($stmt);
$itit = new LimitIterator($it, 10, 20);
foreach ($itit as $user) {
  var_dump($user);
}
Une amélioration possible serait d'étendre NoRewindIterator au lieu de IteratorIterator, mais je n'ai pas encore réussi à la faire marcher dans ce sens...

Voir également la discussion d'origine: http://www.developpez.net/forums/d10...oo-orm-entite/

Vos commentaires sont les bienvenus.
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/03/2011, 21h36   #2
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
A vue de nez, je dirai nikel.

Traversable est compliquée, elle déclare un itérateur interne, donc on peut utiliser foreach() (ça appel fetch()), mais l'itérateur n'est pas visible depuis PHP, pour personnaliser le comportement, faut l'encapsuler dans IteratorIterator, comme tu l'as fait.

NoRewind ne fonctionne pas ?
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/03/2011, 21h38   #3
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
Cette implémentation ne fonctionne pas correctement:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
 
class PDOStatementIterator extends NoRewindIteratro implements SeekableIterator, Countable {
 
    protected $_statement;
 
    protected $_count;
 
    public function __construct (PDOStatement $statement) {
        parent::__construct(new IteratorIterator($this->_statement = $statement));
    }
 
    // ...
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/03/2011, 23h25   #4
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Code :
parent::__construct($this->_statement = $statement);
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/04/2011, 11h46   #5
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
Non car le constructeur de NoRewindIterator attends un Iterator. La solution consiste à wrapper le PDOStatement dans un IteratorIterator avant de le wrapper à son tour par un NoRewindIterator, mais pour une raison qui m'échappe, ça ne fonctionne pas dans le contexte du constructeur... L'objet construit ne se traverse plus.
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/04/2011, 22h42   #6
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
NoRewindIterator extends IteratorIterator
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/04/2011, 14h02   #7
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
La signature de leurs constructeurs est différentes. Essaie tu verras.
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/04/2011, 18h12   #8
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Ahh oui les vilains,ils ont typés sur Iterator et non pas Traversable.

Pas bien ça

Du coup je sais pas, j'ai pas testé le IteratorIterator , mais ça devrait fonctionner.
Bug possible ?
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/04/2011, 18h47   #9
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
J'ai testé à la main avec ça:
Code :
1
2
3
4
 
$stmt = $pdo->prepare('machin truc');
$it = new IteratorIterator($stmt); // traverser cet objet fonctionne
$itit = new NoRewindIterator($it); // ne se traverse pas...
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/04/2011, 21h04   #10
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
C'est plutot louche
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/04/2011, 03h15   #11
stealth35
Modérateur
 
Inscription : septembre 2010
Messages : 7 958
Détails du profil
Informations forums :
Inscription : septembre 2010
Messages : 7 958
Points : 9 508
Points : 9 508
malheureusement on ne pas pas utiliser ce genre de classe direct dans PDO::ATTR_STATEMENT_CLASS sans passer par un pont
__________________
http://blog.stealth35.com/
stealth35 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/04/2011, 11h34   #12
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
Non en effet, à moins de réécrire un iterateur en partant de Iterator.
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/04/2011, 21h33   #13
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Citation:
Envoyé par stealth35 Voir le message
malheureusement on ne pas pas utiliser ce genre de classe direct dans PDO::ATTR_STATEMENT_CLASS sans passer par un pont
Yes, il type sur PDOStatement. C'est une limite interne
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/04/2011, 22h06   #14
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Citation:
Envoyé par Benjamin Delespierre Voir le message
Non en effet, à moins de réécrire un iterateur en partant de Iterator.
Ouai ?

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
class MySt extends PDOStatement implements IteratorAggregate
{
    public function getIterator() {
        return new ArrayIterator($this->fetchAll());
}
}
 
$p = new PDO('sqlite::memory:');
$p->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MySt'));
$p->exec('CREATE TABLE foo (txt TEXT);');
$p->exec("INSERT INTO foo VALUES ('foobar');");
 
var_dump(iterator_to_array($p->query("SELECT * FROM foo")));
 
/*
array(1) {
  [0]=>
  array(2) {
    ["txt"]=>
    string(6) "foobar"
    [0]=>
    string(6) "foobar"
  }
}*/
Ecrit en 2min, utilise fetchAll() à l'arrache. En implémentant Iterator, on peut appeler seulement fetch() à chaque tour.
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/04/2011, 22h45   #15
stealth35
Modérateur
 
Inscription : septembre 2010
Messages : 7 958
Détails du profil
Informations forums :
Inscription : septembre 2010
Messages : 7 958
Points : 9 508
Points : 9 508
Ça perd de beaucoup de son intérêt la, je vois pas comment tu peux implémenter Iterator puisque c'est pas possible de le faire :

Code :
1
2
class Bug38592 extends PDOStatement implements Iterator {}
//Fatal error: Class Bug38592 could not implement interface Iterator in Unknown on line 0
__________________
http://blog.stealth35.com/
stealth35 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/04/2011, 10h25   #16
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Yes, c'est parcequ'il implémente Traversable en interne et ne peut pas implémenter Iterator.

Bloqué !
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/04/2011, 10h43   #17
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
On revient donc sur notre wrapper de départ... Aucune piste en ce qui concerne le NoRewindIterator.
Pour rappel les tests de wrap d'un PDOStatement dans un IteratorIterator ne posent aucun problème, or lorsqu'on met cet IteratorIterator dans un NoRewindIterator, plus rien ne marche...

Voici un exemple:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
$db = "backoffice";
$db_type = "mysql";
$db_user = "root";
$db_password = "";
$db_host = "localhost";
 
$pdo = new PDO("$db_type:dbname=$db;host=$db_host", $db_user, $db_password);
$query = "SELECT * FROM users";
$stmt = $pdo->query($query);
 
$it = new IteratorIterator($stmt);
$itit = new NoRewindIterator($it);
foreach ($itit as $row) {
 var_dump($row);
}
 
var_dump("done");
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/04/2011, 11h53   #18
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Faut regarder si ya pas un rapport de bug à ce sujet.

A tout hasard, tester avec un NoRewindIterator(IteratorIterator) sur autre chose que PDOStatement, pour prouver que le bug supposé vient bien de PDOStatement (pas sûr)
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/04/2011, 12h10   #19
Benjamin Delespierre
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 3 897
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 25
Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 3 897
Points : 8 605
Points : 8 605
Chose étrange, il semble que NoRewindIterator nécéssite un iterateur rembobiné pour fonctionner correctement... Je vais voir la doc à ce sujet.

Voici un exemple:
Code :
1
2
3
4
5
6
7
8
9
 
$a = new ArrayObject(array(1,2,3,4,5));
 
$it = new IteratorIterator($a);
$it->rewind(); // Si on commente cette ligne, le NoRewindIterator ne se traverse plus...
 
$itit = new NoRewindIterator($it);
foreach ($itit as $val)
  echo $val;
A noter que cette forme fonctionne parfaitement:
Code :
1
2
3
4
5
6
 
$a = new ArrayIterator(array(1,2,3,4,5));
 
$itit = new NoRewindIterator($a); // On a besoin d'un Iterator ici
foreach ($itit as $val)
  echo $val;
__________________
On vous a menti
PHP, Injection de dépendances et composants
La POO en PHP en 10 minutes pour moins
Suivez-moi sur GitHub et Twitter

N'oubliez pas de vous servir des bouttons , et
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/04/2011, 12h29   #20
doctorrock
Rédacteur
 
Avatar de doctorrock
 
Homme Julien Pauli
Architecte de système d'information
Inscription : mai 2006
Messages : 603
Détails du profil
Informations personnelles :
Nom : Homme Julien Pauli
Âge : 30
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Architecte de système d'information
Secteur : High Tech - Produits et services télécom et Internet

Informations forums :
Inscription : mai 2006
Messages : 603
Points : 3 926
Points : 3 926
Idem sur le Caching ; ça , c'est un bug ! (déja vu, relevé, mais pas corrigé il me semble)
__________________
.: Expert contributeur certifié PHP/ZF :.
Mes articles - Twitter - GitHub
doctorrock est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 10h20.


 
 
 
 
Partenaires

Hébergement Web