Résoudre vos problématiques de fuite mémoire avec Garbage Collector & yield

logo_php

Le Garbage Collector ou ramasse-miettes (Plus d'infos) a fait son apparition à partir de la version  PHP  5.3.0. Nous pouvons dire que c'est une solution pour les problématiques liées aux fuites mémoire que rencontre plusieurs développeurs PHP en matière de récupération du résultat d'une requête ou d'affectation de données volumineuses  dans un tableau PHP .

Ils sont souvent en face d'une erreur bien connue :  "Fatal error: Allowed memory size". Mais alors que faire ? C'est ce que je vais vous expliquer dans cet article.

Prenons l'exemple d'une table "commandes" qui a plus de 1 000 000 de lignes dont nous devons effectuer l'export CSV en php.

    
    /**
     * queryManager utilisation de yield pour eviter les problème de mémoire des tableaux 
     * @param string $query requete sql
     * @param array  $params liste des paramètres
     * @return object
     */
    public function queryManager($query, $params = array())
    {
        $entityManager = \Zend_Registry::get('doctrine')->getEntityManager();
        $pdo = $entityManager->getConnection(); // Récupérartion de la connexion avec doctrine
        gc_enable(); //Activation du Garbage Collector
        $stmt = $pdo->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
        $stmt->execute($params);

            while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
                yield $rs; //parcours du générateur avec mise en pause de l'exécution.
                gc_collect_cycles(); //On force le passage du collecteur de mémoire
            }
        }
    }
Methode doctrine pdo

Yield est un générateur php introduit dans php 5.5, issu des langages comme Python. Il nous permet de pouvoir copier dans un tableau php un nombre volumineux de données sans avoir en retour des problèmes de mémoire.

Le résultat de cette méthode est un générateur sur lequel nous pouvons inclure une boucle php afin de récupérer les résultats. Plus infos sur yield

Exemple d’implémentation :

/**
     * Traitement requête export 
     * @return array
     */
    public function myQueryTest() 
    {
        
        $myExport = array();
        $query = 'select code, libelle from commandes'
        $result =  $this->queryManager($query); //retourne plus de 1 000 000  de lignes pour le tableau
        
        // on boucle sur l'objet yield
        foreach ($result as $key => $value) {
             $myExport[$key]['Code commande'] = $value->code;
             $myExport[$key]['Libelle commande'] = $value->libelle;
        }
        
        return array('fileName' => 'Liste-commande', 'datas' => $myExport);
    }
    
    /**
     * return csv telechargé
     */
    public function myExportAction() 
    {
        
        //Récupération de la liste 
        $list = $this->myQueryTest();
        $mData= $list['datas'];
        $fileName = $list['fileName'];
        
        // force download php pour le csv
    }

Et voilà comment résoudre votre problème en toute simplicité !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.