IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Affichage des résultats du sondage: Que retournez-vous ?

Votants
4. Vous ne pouvez pas participer à ce sondage.
  • tableau

    0 0%
  • collection

    4 100,00%
  • recordset

    0 0%
Langage PHP Discussion :

POO ORM Entité


Sujet :

Langage PHP

  1. #1
    Membre habitué
    Inscrit en
    Avril 2003
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Avril 2003
    Messages : 397
    Points : 133
    Points
    133
    Par défaut POO ORM Entité
    Bonjour,

    Prenons un exemple : vous souhaitez retourner la liste des utilisateurs.

    Vous créez une méthode (static par exemple), dans une classe "User".

    Que retourner vous ?
    - un tableau,
    - une collection (d'objets),
    - le recordset directement issu de la requête.

    La collection semble vraiment être la solution la plus propre et maintenable, mais aussi la plus lourde.

    Pourquoi parcourir le recordset pour créer un tableau manuellement à retourner alors que le code qui va appeler la méthode va re-parcourir ce même tableau (donc 2 parcours) ?

    Comment vous y prenez-vous ? Pourquoi ?

    Merci

  2. #2
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Pour ma part je stocke une collection d'objet et je libère la ressource SQL.

    Pourquoi pas un tableau ? Parce que je trouve plus propre et plus personnalisable d'utiliser des objets.

    Pourquoi pas le recordset ? Parce que garder indéfiniment des tonnes de recordset en mémoire n'est pas franchement optimisé.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  3. #3
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Je récupère dans une collection qui fonctionne en lazy loading.

    J'utilise ensuite un Iterator qui me permet de créer les objets sur demande, cela évite la charge inutile. De plus le fait d'utiliser un Iterator permet l'usage du LimitIterator qui est bien pratique pour la pagination.

  4. #4
    Membre habitué
    Inscrit en
    Avril 2003
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Avril 2003
    Messages : 397
    Points : 133
    Points
    133
    Par défaut
    Le problème du lazyload dans un parcours c'est qu'il va exécuter N requêtes pour récupérer l'objet.

    OK pour l'objet y'a pas photo, mais les "new" sont très gourmands alors que l'on possède déjà toutes les données "à plat" dans le recordset ?

  5. #5
    Expert éminent
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 146
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 146
    Points : 9 386
    Points
    9 386
    Par défaut
    Mais en cas de grosse requête le recordset est très lourd aussi, de plus cela peut gêner les prochaines requêtes si tu ne le libères pas.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  6. #6
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Le problème du lazyload dans un parcours c'est qu'il va exécuter N requêtes pour récupérer l'objet.
    En effet, mais cette solution est plus pratique que performante. Ceux qui veulent une performance accrue peuvent utiliser PDO::FETCH_INTO ou PDO::FETCH_CLASS. Le problème est que bien que le PDOStatement soit traversable il n'implémente pas Iterator et donc, pas de LimitIterator (ou autres FilterIterator). On devrait cependant pouvoir faire un PDOStatementIterator sans trop se casser la tête, c'est à creuser...

    OK pour l'objet y'a pas photo, mais les "new" sont très gourmands alors que l'on possède déjà toutes les données "à plat" dans le recordset ?
    Je fais ça en deux passes (je sais pertinemment que ce n'est pas optimal):
    - une query réccupère les id et les passe à un RecordsetIterator en lui fournissant le nom de la classe à invoquer pour le fech.
    - la méthode current du RecordsetIterator génère les objets pour l'id courant.
    L'idée n'est bien sûr pas d'appliquer ce traitement sur de larges ensembles d'objets mais sur des sous-ensemble des 10 ou 20 éléments.

    Mais en cas de grosse requête le recordset est très lourd aussi, de plus cela peut gêner les prochaines requêtes si tu ne le libères pas.
    Cela dépends de ton driver.

    Voici à quoi ressemble le recordset (réduit à sa plus simple expression):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    class RecordsetIterator extends ArrayIterator {
     
        protected $_class;
     
        public function __construct ($array, $class) {
            if (!$class || !class_exists($class, true))
                throw new RuntimeException("Unknown class $class");
     
            parent::__construct($array);
            $this->_class = $class;
        }
     
        public function current () {
            return new $this->_class (parent::current());
        }
    }
    Voici comment il est utilisé par une méthode d'un modèle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
        public static function getArticles () {
            $query = "SELECT `id` FROM `blog`.`articles`";
     
            if ($stmt = Database::query($query)) {
                $results = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
                return new RecordsetIterator(array_map('implode', $results), __CLASS__);
            }
            return false;
        }
    -- Edit
    Si j'ai le temps je fournirai un prototype pour le PDOStatementIterator évoqué plus haut.

  7. #7
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    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 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Voici à quoi pourrait bien ressembler notre StatementIterator.
    Pour l'utiliser comme un factory d'objet, il est nécéssaire de définir le fetch-mode de PDOStatement avant d'instancier cette classe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    <?php
     
    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())
                throw new OutOfBoundsException("Cannot seek to $position");
     
            if ($position < $this->key())
                throw new OutOfRangeException("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;
        }
    }
     
    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;
      }
    }
    Il s'utilise ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    echo "<pre>";
     
    $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);
     
    $user = new User;
     
    $stmt = $pdo->prepare('SELECT * FROM `backoffice`.`users`');
    $stmt->setFetchMode(PDO::FETCH_INTO, $user);
    $stmt->execute();
     
    $it = new PDOStatementIterator($stmt);
     
    var_dump(count($it));
    foreach ($it as $user) { var_dump($user); }
     
    echo "</pre>";
    Vos commentaires sont les bienvenus.

Discussions similaires

  1. [2.x] comprendre : entité + model + orm.xml
    Par walter75 dans le forum Symfony
    Réponses: 3
    Dernier message: 25/04/2014, 13h53
  2. [PHP 5.2] [POO] Orm SQLite
    Par Doki95 dans le forum Langage
    Réponses: 4
    Dernier message: 12/11/2009, 19h28
  3. [POO] Différence entre ORM et Active Record ?
    Par Jokaritaff dans le forum Langage
    Réponses: 6
    Dernier message: 25/05/2008, 16h10
  4. [DOM] [Xerces] Insertion d'une entité
    Par Traroth dans le forum Format d'échange (XML, JSON...)
    Réponses: 10
    Dernier message: 19/05/2008, 09h28
  5. [MSXML] Comment empécher la conversion des entités ?
    Par nima dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 08/11/2002, 14h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo