
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é !