Précédent   Forum des professionnels en informatique > PHP > Langage > Fonctions
Fonctions Forum d'entraide sur les fonctions PHP. Avant de poster -> FAQ fonctions et Sources diverses
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 12/02/2011, 08h41   #1
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Par défaut Fonction récursive pour remplissage Array

Bonjour à tous, j'espère tout d'abord poster au bon endroit ;

J'ai bien utilisé la fonction de recherche avant, et trouvé une question presque similaire à la mienne, mais le résultat ne me convenait pas (requête dans une boucle, berk.)

Voilà mon soucis :

J'extrais d'une base les informations sur des forums (ID, titre, etc.).
Chaque forum possède un champ 'parent_forum_id', qui peut avoir une valeur NULL. Si NULL, alors le forum est en première ligne, sans parent. Sinon, c'est le sous-forum du parent précisé.

Du coup, je me retrouve avec un résultat ligne par ligne de forums / sous-forums, et je dois refaire l'arbre ; le but est de refaire cet arbre sous forme d'Array, qui pourra être exploité ultérieurement..



Voici mon script à l'heure actuelle, qui permet d'avoir dans l'array :

Les catégories et leurs infos, plus un champ 'children', qui contient NULL par défaut, puis qui contient les array des forums qu'il contient, avec leurs infos, plus un champ 'children', etc.

J'arrive à créer l'Array avec les catégories, puis à y insérer les Forums sans parents, puis à insérer par le biais d'une fonction les premiers sous-forums ; mais impossible, pour mon pauvre esprit, de concevoir la fonction en mode récursif pour continuer dans la "généalogie"..

Je comprends bien le concept d'une fonction récursive, mais juste, mes syntaxes finissent par planter (des erreurs d'index inexistants, ou encore de mémoire dépassée)

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
require('conf/conf.inc.php');
$categories = $c->get("SELECT * FROM categories");
$for_parents = $c->get("SELECT * FROM forums WHERE parent_forum_id IS NULL");
$for_children = $c->get("SELECT * FROM forums WHERE parent_forum_id IS NOT NULL");
 
$site = array();
$enfants = array();
 
foreach($categories as $cat){	
	$site[$cat['cat_id']] = $cat;
	$site[$cat['cat_id']]['children'] = NULL;
}
foreach($for_parents as $forum){
	$site[$forum['cat_id']]['children'][$forum['forum_id']] = $forum;
	$site[$forum['cat_id']]['children'][$forum['forum_id']]['children'] = NULL;
}
foreach($for_children as $forum){
	$enfants[$forum['forum_id']] = $forum;
}
 
function addEnfants($parents, $enfants){
	foreach($parents as $key=>&$parent){
		foreach($enfants as &$enf){
			if($enf['parent_forum_id'] == $key){
				$parent['children'][$enf['forum_id']] = $enf;
				$parent['children'][$enf['forum_id']]['children'] = NULL;
				// ICI, je suis censé placer un "unset" pour vider petit à petit l'array des enfants, puis relancer la fonction "addEnfant()". C'est à cette ligne que je bloque...
			}
		}
	}
	return $parents;
}
 
foreach($site as &$parents){
	$parents = addEnfants($parents['children'], $for_children);
}
unset($parents);
 
echo '<pre>';
var_dump($site);
echo '</pre>';
echo '<br />--------------<br />';
?>

Si quelqu'un a une idée pour me décoincer Merci !
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/02/2011, 16h26   #2
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Je post la suite de mon problème, ayant avancé seul..

J'ai réussi à créer ma fonction, et le résultat est quasiement bon ; le seul bémol, c'est qu'au résultat final, mon array est correctemetn construit mais j'ai perdu au passage toute information concernant les catégories et les 1ers forums.

Les sous-forums, quant à eux, sont parfaitement en place avec toutes leurs informations (titre, etc..)

voilà mon script à l'heure actuelle :

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
require('conf/conf.inc.php');
$categories = $c->get("SELECT * FROM categories");
$for_parents = $c->get("SELECT * FROM forums WHERE parent_forum_id IS NULL");
$for_children = $c->get("SELECT * FROM forums WHERE parent_forum_id IS NOT NULL");
 
$site = array();
$enfants = array();
 
function addEnfants($parents, $enfants){
	foreach($parents as $key=>&$parent){
		foreach($enfants as &$enf){
			if($enf['parent_forum_id'] == $parent['forum_id']){
				$parent['children'][$enf['forum_id']] = $enf;
				$parent['children'][$enf['forum_id']]['children'] = NULL;
				$parent['children'] = addEnfants($parent['children'], $enfants);
			}
 
		}
	}
	return $parents;
}
 
// Initialisation des catégories
foreach($categories as $cat){
	$site[$cat['cat_id']] = $cat;
	$site[$cat['cat_id']]['children'] = NULL;
}
// Initialisation des forums sans parents
foreach($for_parents as $forum){
	$site[$forum['cat_id']]['children'][$forum['forum_id']] = $forum;
	$site[$forum['cat_id']]['children'][$forum['forum_id']]['children'] = NULL;
}
// On récupère tous les sous-forums
foreach($for_children as $forum){
	$enfants[$forum['forum_id']] = $forum;
}
// On créé le tableau contenant l'arbre
foreach($site as &$parents){
	$parents = addEnfants($parents['children'], $for_children);
}
unset($parents);
 
echo '<pre>';
var_dump($site);
echo '</pre>';
echo '<br />--------------<br />';
?>
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/02/2011, 18h09   #3
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
Salut WibiMaster,

Citation:
le seul bémol, c'est qu'au résultat final, mon array est correctemetn construit mais j'ai perdu au passage toute information concernant les catégories et les 1ers forums.
C'est normal car ta fonction addEnfant devrait travailler avec des références et non des copies de tableaux :
Code :
function addEnfant(&$parents, &$enfants)
Enfin si je ne suis pas à côté de la plaque.

De mon côté j'ai eu à faire un truc de ce genre et je te l'ai adapté (grosso modo) à tes besoins j'y ai mis des annotations dans le code histoire de ne pas être paumé. Je ne saurais que trop te conseiller de te pencher sur la SPL (Standard PHP Library) car elle offre des tas de fonctions sacrément utiles par exemple dans le cas de la récursivité. Et pour ne rien gâcher la récursivité est mise à plat et du coup tu ne risque pas de mettre à genoux le serveur en cas d'algorithme attaquant des données très volumineuses (vécu).
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
 
require('conf/conf.inc.php');
 
$categs = $c->get("SELECT * FROM categories");
# il faut absolument avoir les forums parents avant les enfants
$forums = $c->get("SELECT * FROM forums ORDER BY parent_forum_id");
 
$map   = array();
$paths = array();
 
# récupération de toutes les catégories
# pour profiter de la SPL (voir plus bas) il fallait éviter
# les collisions entre les clés des cat_id et des forum_id
# donc j'ai préfixé les cat_id avec un 'g'
foreach($categs as $cat) {
   $map['g' . $cat['cat_id']] = array('type'      => 'categ',
                                      'details'    => $cat, 
                                      'subforums'  => array());
}
 
# arborescence des forums
foreach($forums as $forum) {
 
   $idParent = $forum['parent_forum_id'];
   $idForum  = $forum['forum_id'];
 
   if (is_null($idParent)) {
      # forum racine
      $map['g' . $forum['cat_id']]['subforums'] += array($idForum => array('type'      => 'forum',
                                                                           'details'   => $forum, 
                                                                           'subforums' => array()));
      # chemin vers le forum courant
      $paths[$idForum] = array('g' . $forum['cat_id']);
 
   } else {
      # sous-forum
      # chemin vers le forum courant
      $paths[$idForum] = array_merge($paths[$idParent], array($idParent));
 
      foreach (new RecursiveIteratorIterator(
                  new RecursiveArrayIterator($map),
                        RecursiveIteratorIterator::SELF_FIRST) as $key => $value) 
      {
         # si la clé courante correspond à la clé recherchée
         # on ajoute le sous-forum au tableau $map
         if ($key == $idParent) {
            $nb = count($paths[$idForum]) - 1;
            for($i = 0; $i <= $nb; $i++) {
               if ($i == 0) {
                  $last =& $map[$paths[$idForum][$i]];
               } else {
                  $last =& $last['subforums'][$paths[$idForum][$i]];
               }
            }
            $last['subforums'] += array($idForum => array('type'      => 'forum',
                                                          'details'   => $forum,
                                                          'subforums' => array()));
         }
      }
   }
   var_dump($map);
}
?>
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/02/2011, 18h24   #4
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Merci !

Déjà pour l'histoire des références, il me semblait qu'en la déclarant avec le "&" dans le foreach, je pouvais l'utiliser sans après.. Mais je me trompe peut-être.

J'ai donc testé ton script, ça fonctionne presque ; les sous-forums de sous-forums ne sont pas pris en compte, et j'obtiens assez régulièrement l'erreur :

Warning: Cannot use a scalar value as an array in C:\Program Files (x86)\EasyPHP-5.3.3\www\live4dev\test2.php on line 53

dans le var_dump..
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/02/2011, 18h39   #5
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
Oui j'ai fait une boulette dans la ligne 53
remplace $last &= par
Code :
1
2
3
4
5
if ($i == 0) {
   $last =& $map[$paths[$idForum][$i]];
} else {
   $last =& $last['subforums'][$paths[$idForum][$i]];
}
Dans tous les cas j'ai essayé avec ce genre de données :
Code :
1
2
3
4
5
6
7
8
9
10
$categs = array(array('cat_id' => 0, 'nom' => 'PHP'), 
                array('cat_id' => 1, 'nom' => 'JAVA'), 
                array('cat_id' => 2, 'nom' => 'VBA'));
 
$forums = array(array('forum_id' => 1, 'cat_id' => 0, 'nom' => 'Général'),
                array('forum_id' => 2, 'parent_forum_id' => 1, 'nom' => 'Code'),
                array('forum_id' => 3, 'parent_forum_id' => 1, 'nom' => 'Syntaxe'),
                array('forum_id' => 4, 'parent_forum_id' => 1, 'nom' => 'Langage'),
                array('forum_id' => 5, 'parent_forum_id' => 4, 'nom' => 'Débutant'),
                array('forum_id' => 6, 'parent_forum_id' => 4, 'nom' => 'Confirmé'));
Et j'ai bien toute l'arborescence
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 09h09   #6
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Presque bon xD

C'est la première fois que j'utilise les RecursiveIteratorIterator, alors je prends mon temps pour lire, comprendre, en utilisant la doc.

En tout cas, c'est quasiement bon, mais ça plantait (serveur down) quand je lançais la page. Alors j'ai essayé avec tes données, moins importantes que les miennes, et ça plante aussi.

En coupant le chargement de la page au bout de quelques secondes avant que tout pète, j'ai pu remarquer qu'en fait, la boucle ne s'arrêtait jamais ; je retrouve

array(3) {
["g0"]=>

donc l'origine, plusieurs fois. Comme si toute la page se relançait sans arrêt, donc forcément, tout plante. J'essaie de voir où le script devrait détecter la fin et s'arrêter, pour l'améliorer ; étrange que cela fonctionne correctement chez toi, j'ai pourtant repris point par point tout ce que tu m'as donné..

Les lignes

Code :
1
2
$last &= ($i == 0) ? $map[$paths[$idForum][$i]]
                                  : $last['subforums'][$paths[$idForum][$i]];
sont bien devenues

Code :
1
2
3
4
5
if ($i == 0) {
					$last =& $map[$paths[$idForum][$i]];
				} else {
					$last =& $last['subforums'][$paths[$idForum][$i]];
				}
Mais c'est depuis que le script ne s'arrête pas ; j'ai du faire une erreur ici, je cherche et je tiens au courant ^^

Merci de ton aide !

[edit]
En réalité, j'ai bien observer le var_dump (meme arreté avant la fin) ; ce n'est pas que le code se répète indéfiniment (quoi que, sans doute tout de même), c'est assez étrange ce qu'il ressort...

Tout d'abord, ça me ressort l'array des catégories ; ensuite, l'array des catégories avec le premier forum ; ensuite, la meme chose mais avec plus de forums ; et ainsi de suite.. Comme s'il faisait un var_dump au fur et à mesure, alors que celui-ci est séparé de la boucle.

Après vérification, celui-ci était bien dans la boucle. Je l'ai donc ressorti, et du coup, ça plante avant de faire le var_dump, je ne vois donc même pas ce qu'il peut contenir. La boucle ne s'arrête réellement jamais.. Je ne comprends pas, dans ton script, c'est un foreach sur un tableau fini, il ne devrait donc pas tourner éternellement...

Ca doit etre à ce niveau là :

Code :
1
2
3
foreach (new RecursiveIteratorIterator(
                  new RecursiveArrayIterator($map),
                        RecursiveIteratorIterator::SELF_FIRST) as $key => $value)
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 10h57   #7
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
Salut WibiMaster,

Bon je t'explique pourquoi chez moi cela a marché : je l'ai exécuté en mode debug avec un point d'arrêt sur var_dump($map) et avec le débug de PHPED j'ai inspecté le contenu de la variable $map et vu qu'il me parraissait correct, je coupais le sifflet au script sans le terminer proprement (J'avais sorti le var_dump de la boucle foreach). C'est la raison pour laquelle je n'ai pas vu que le script bouclait sans fin. J'suis un âne quand même parfois

Je pense le hic se situe dans le fait que l'on modifie le tableau $map tout en le parcourant récursivement et ça doit poser problème à la SPL.

Je me penche dessus.
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 10h59   #8
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Test après test, j'ai cibler le probleme un peu plus bas ;

La boucle ne devrait pas etre infini, le $nb dans l'exemple vaut 1 à chaque tour. donc le

for($i = 0; $i < $nb [...]

devrait s'arreter au bout d'un tour, ce qu'il n'a pas l'air de faire..

Ca semble bloquer au niveau du

$last =&

le truc, c'est que je n'arrive pas à comprendre cette syntaxe, même après recherche

La boucle entière :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
         # si la clé courante correspond à la clé recherchée
         # on ajoute le sous-forum au tableau $map
         if ($key == $idParent) {
            $nb = count($paths[$idForum]) - 1;
				//echo $nb.'--';
            for($i = 0; $i <= $nb; $i++) {
               /*$last &= ($i == 0) ? $map[$paths[$idForum][$i]]
                                  : $last['subforums'][$paths[$idForum][$i]];*/
				if ($i == 0) {
					$last =& $map[$paths[$idForum][$i]];
				} else {
					$last =& $last['subforums'][$paths[$idForum][$i]];
				}
            }
            $last['subforums'] += array($idForum => array('type'      => 'forum',
                                                          'details'   => $forum,
                                                          'subforums' => array()));
         }
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 11h16   #9
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
Citation:
$last =&

le truc, c'est que je n'arrive pas à comprendre cette syntaxe, même après recherche
Cela veut dire que la variable $last pointe vers la même zone mémoire que ce qui est défini à droite de l'opérande =& (en l'occurrence ici une partie du tableau $map), on travaille directement sur le tableau original sans le dupliquer.
J'ai fait un essai sans rien modifer au script mais juste en rajoutant exit(); après le var_dump() et là tu as bien le rendu.
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 11h29   #10
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
ça y est l'os n'est plus :-)

Tu conserves tout le script tel quel et tu lui rajoute un minable après
Code :
1
2
3
$last['subforums'] += array($idForum => array('type'      => 'forum',
                                                          'details'   => $forum,
                                                          'subforums' => array()));
Je remet la partie corrigée :
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# arborescence des forums
foreach($forums as $forum) {
 
   $idParent = $forum['parent_forum_id'];
   $idForum  = $forum['forum_id'];
 
   if (is_null($idParent)) {
      # forum racine
      $map['g' . $forum['cat_id']]['subforums'] += array($idForum => array('type'      => 'forum',
                                                                           'details'   => $forum, 
                                                                           'subforums' => array()));
      $paths[$idForum] = array('g' . $forum['cat_id']);
 
   } else {
      # sous-forum
      # on sauveagrde le chemin vers le forum courant
      $paths[$idForum] = array_merge($paths[$idParent], array($idParent));
 
      foreach(new RecursiveIteratorIterator(
                  new RecursiveArrayIterator($map),
                        RecursiveIteratorIterator::SELF_FIRST) as $key => $value) 
      {
         # si la clé courante correspond à la clé recherchée
         # on ajoute le sous-forum au tableau $map
         if ($key == $idParent) {
            $nb = count($paths[$idForum]) - 1;
            for($i = 0; $i <= $nb; $i++) {
               if ($i == 0) {
                  $last =& $map[$paths[$idForum][$i]];
               } else {
                  $last =& $last['subforums'][$paths[$idForum][$i]];
               }
            }
            $last['subforums'] += array($idForum => array('type'      => 'forum',
                                                          'details'   => $forum,
                                                          'subforums' => array()));
            break;
         }
      }
   }
}
 
var_dump($map);
Voili voilou,

Bon dev
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 13/02/2011, 12h00   #11
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16


Rien à redire... Respect.

Et surtout un énorme merci parce qu'en plus tu post les explications avec, et ça c'est génial pour apprendre de ses erreurs

Bon, ça plante avec ma récupération de données, mais ça doit venir des arrays qui ressortent, je reglerais ça rapidement vu que ça marche avec les tiens qui semblent similaires.

Je marque résolu, et je t'en dois une belle !

Je te copyrighterais à l'occasion si dans mon entourage je vois un problème similaire :p

Encore merci !!!
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 15h29   #12
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Citation:
Et pour ne rien gâcher la récursivité est mise à plat et du coup tu ne risque pas de mettre à genoux le serveur en cas d'algorithme attaquant des données très volumineuses (vécu).
Je n'ai que 19 lignes dans ma table, et je dépasse déjà la mémoire allouée au lancement du script

[EDIT]
Après vérification, le foreach sur le new RecursiveIteratorIterator fais quelques centaines de tours avant de planter, alors que je n'ai que 19 lignes... Il y a donc bien un problème, autre que le break que l'on a placé..
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 16h18   #13
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
Salut,

Tu peux aussi écrire le foreach comme ça et fais un essai avec tes données :
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# arborescence des forums
foreach($forums as $forum) {
 
   $idParent = $forum['parent_forum_id'];
   $idForum  = $forum['forum_id'];
 
   if (is_null($idParent)) {
      # forum racine
      $map['g' . $forum['cat_id']]['subforums'] += array($idForum => array('type'      => 'forum',
                                                                           'details'   => $forum, 
                                                                           'subforums' => array()));
      $paths[$idForum] = array('g' . $forum['cat_id']);
 
   } else {
      # sous-forum
      # on sauveagrde le chemin vers le forum courant
      $paths[$idForum] = array_merge($paths[$idParent], array($idParent));
 
      $arIter = new RecursiveArrayIterator($map);
      $itIter = new RecursiveIteratorIterator($arIter, RecursiveIteratorIterator::SELF_FIRST);
      /*
      foreach(new RecursiveIteratorIterator(
                  new RecursiveArrayIterator($map),
                        RecursiveIteratorIterator::SELF_FIRST) as $key => $value) 
 
      */
      foreach($itIter as $key => $value)
      {
         # si la clé courante correspond à la clé recherchée
         # on ajoute le sous-forum au tableau $map
         if ($key == $idParent) {
            $nb = count($paths[$idForum]) - 1;
            for($i = 0; $i <= $nb; $i++) {
               if ($i == 0) {
                  $last =& $map[$paths[$idForum][$i]];
               } else {
                  $last =& $last['subforums'][$paths[$idForum][$i]];
               }
            }
            $last['subforums'] += array($idForum => array('type'      => 'forum',
                                                          'details'   => $forum,
                                                          'subforums' => array()));
            break;
         }
      }
   }
}
 
var_dump($map);
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 16h33   #14
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Cela plante également...

J'ai mis le break en dehors de la condition, et ça ne plante plus ; cependant, ça ne me prends pas en compte les sous forums.

Ci-joint un aperçu de mes tables catégories et forums, donc qui ressortent comme ton exemple d'array... (avec un sous-forum en plus, je ne sais pas si ça change grand chose..)

La boucle fait vraiment trop de tour, elle fais plus que boucler sur l'array uniquement



[EDIT]
J'ai fais un test en initialisant le nombre de tour à 0 avant le foreach problematique, et en faisant un echo de ce nombre incrémenter de 1 à chaque tour ; ça plante, quand j'en arrive à 169228.

Je mets mon code dans son intégralité, sait-on jamais... (j'ai ré-ordonner les données sorties, le var_dump donne bien le résultat attendu)

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
 
<?php
//echo memory_get_usage().'<br />';
require('conf/conf.inc.php');
$categories = $c->get("SELECT * FROM categories");
# il faut absolument avoir les forums parents avant les enfants
$forumies = $c->get("SELECT * FROM forums ORDER BY parent_forum_id");
 
$categs = array();
foreach($categories as $ca){
	$categs[] = array(
		'cat_id' => (int) $ca['cat_id'],
		'cat_titre' => (string) $ca['cat_titre'],
		'cat_description' => (string) $ca['cat_description']
	);
}
$forums = array();
foreach($forumies as $fo){
	$forums[] = array(
		'parent_forum_id' => ($fo['parent_forum_id'])?(int) $fo['parent_forum_id']:null,
		'cat_id' => (int) $fo['cat_id'],
		'forum_id' => (int) $fo['forum_id'],
		'forum_titre' => (string) $fo['forum_titre'],
		'forum_description' => (string) $fo['forum_description']
	);
}
asort($forums);
 
$map   = array();
$paths = array();
# récupération de toutes les catégories
# pour profiter de la SPL (voir plus bas) il fallait éviter
# les collisions entre les clés des cat_id et des forum_id
# donc j'ai préfixé les cat_id avec un 'g'
//echo memory_get_usage().'<br />';
foreach($categs as $cat){
	$map['g' . $cat['cat_id']] = array('type'       => 'categ',
									   'details'    => $cat,
									   'subforums'  => array());
}
//echo memory_get_usage().'<br />';
# arborescence des forums
foreach($forums as $forum){
	$idParent = $forum['parent_forum_id'];
	$idForum  = $forum['forum_id'];
	if(is_null($idParent)){
		# forum racine
		$map['g' . $forum['cat_id']]['subforums'] += array($idForum => array('type'      => 'forum',
																			 'details'   => $forum, 
																			 'subforums' => array()));
		# chemin vers le forum courant
		$paths[$idForum] = array('g' . $forum['cat_id']);
   }else{
		# sous-forum
		# chemin vers le forum courant
		$paths[$idForum] = array_merge($paths[$idParent], array($idParent));
 
      $arIter = new RecursiveArrayIterator($map);
      $itIter = new RecursiveIteratorIterator($arIter, RecursiveIteratorIterator::SELF_FIRST);
      /*
      foreach(new RecursiveIteratorIterator(
                  new RecursiveArrayIterator($map),
                        RecursiveIteratorIterator::SELF_FIRST) as $key => $value){
 
      */
	  $tour = 0;
      foreach($itIter as $key => $value)
      {
			$tour++;
			echo $tour.'<br />';
			# si la clé courante correspond à la clé recherchée
			# on ajoute le sous-forum au tableau $map
			//echo memory_get_usage().'<br />';
			if($key == $idParent){
				$nb = count($paths[$idForum]) - 1;
				for($i = 0; $i <= $nb; $i++){
					if($i == 0){
						$last =& $map[$paths[$idForum][$i]];
					}else{
						$last =& $last['subforums'][$paths[$idForum][$i]];
					}
				}
				$last['subforums'] += array($idForum => array('type'      => 'forum',
															  'details'   => $forum,
															  'subforums' => array()));
				break;
			}
 
		}
	}
}
echo '<pre>';
var_dump($map);
echo '</pre>';
?>
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/02/2011, 20h04   #15
Expert Confirmé
 
Avatar de rawsrc
 
Homme Martin
Dev indep
Inscription : mars 2004
Messages : 1 461
Détails du profil
Informations personnelles :
Nom : Homme Martin
Âge : 35
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

Informations professionnelles :
Activité : Dev indep

Informations forums :
Inscription : mars 2004
Messages : 1 461
Points : 2 548
Points : 2 548
Envoyer un message via Skype™ à rawsrc
Décidemment il y a des jours où il faudrait mieux rester couché.

Bon comme je suis un sale entêté teigneux, j'ai continué à creuser et voici ce que je te propose. J'ai quand même un peu honte car c'est désarmant de simplicité.
Je t'y ai mis aussi un tableau de données qui me faisait le même dépassement de mémoire que toi avec le RecursiveIteratorIterator/RecursiveArrayIterator.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php
 
$categs = array(array('cat_id' => 0, 'nom' => 'PHP'), 
                array('cat_id' => 1, 'nom' => 'JAVA'), 
                array('cat_id' => 2, 'nom' => 'VBA'));
 
$forums = array(array('forum_id' => 1, 'cat_id' => 0, 'nom' => 'Général'),
                array('forum_id' => 2, 'parent_forum_id' => 1, 'nom' => 'Code'),
                array('forum_id' => 3, 'parent_forum_id' => 1, 'nom' => 'Syntaxe'),
                array('forum_id' => 4, 'parent_forum_id' => 1, 'nom' => 'Langage'),
                array('forum_id' => 5, 'parent_forum_id' => 4, 'nom' => 'Débutant'),
                array('forum_id' => 6, 'parent_forum_id' => 4, 'nom' => 'Confirmé'),
                array('forum_id' => 7, 'cat_id' => 2, 'nom' => 'Général'),
                array('forum_id' => 8, 'parent_forum_id' => 7, 'nom' => 'Code'),
                array('forum_id' => 9, 'parent_forum_id' => 7, 'nom' => 'Syntaxe'),
                array('forum_id' => 10, 'parent_forum_id' => 7, 'nom' => 'Langage'),
                array('forum_id' => 11, 'parent_forum_id' => 10, 'nom' => 'Débutant'),
                array('forum_id' => 12, 'parent_forum_id' => 10, 'nom' => 'Confirmé'),
                array('forum_id' => 13, 'cat_id' => 1, 'nom' => 'Général'),
                array('forum_id' => 14, 'parent_forum_id' => 13, 'nom' => 'Code'),
                array('forum_id' => 15, 'parent_forum_id' => 13, 'nom' => 'Syntaxe'),
                array('forum_id' => 16, 'parent_forum_id' => 13, 'nom' => 'Langage'),
                array('forum_id' => 17, 'parent_forum_id' => 16, 'nom' => 'Débutant'),
                array('forum_id' => 18, 'parent_forum_id' => 16, 'nom' => 'Confirmé'));
 
$map   = array();
$paths = array();
 
# récupération de toutes les catégories il fallait éviter
# les collisions entre les clés des cat_id et des fourm_id
# donc j'ai préfixé les cat_id avec un 'g'
foreach($categs as $cat) {
   $map['g' . $cat['cat_id']] = array('type' => 'categ',
                                      'details'    => $cat, 
                                      'subforums'  => array());
}
 
# arborescence des forums
foreach($forums as $forum) {
 
   $idParent = $forum['parent_forum_id'];
   $idForum  = $forum['forum_id'];
 
   $current = array($idForum => array('type'      => 'forum',
                                      'details'   => $forum, 
                                      'subforums' => array()));
 
   if (is_null($idParent)) {
      # forum racine
      $map['g' . $forum['cat_id']]['subforums'] += $current;
      $paths[$idForum] = array('g' . $forum['cat_id']);
 
   } else {
      # sous-forum
      # on sauvegarde le chemin vers le forum courant
      $paths[$idForum] = array_merge($paths[$idParent], array($idParent));
 
      $nb = count($paths[$idForum]);
      for($i = 0; $i < $nb; $i++) {
         if ($i == 0) {
            $last =& $map[$paths[$idForum][$i]];
         } else {
            $last =& $last['subforums'][$paths[$idForum][$i]];
         }
      }
      $last['subforums'] += $current;
   }
}
 
var_dump($map);
 
?>
Et là tu vas me dire comment n'y ai-je pas pensé plutôt et bien saches que je n'en sais rien, si c'est bon tu peux me noter et si cela foire tu pourras me fouetter, promis
Je me suis absenté 2 heures et au retour ça m'a fait splash boum la-dedans.

De mon côté je n'arrive pas à expliquer pourquoi un banal RecursiveIteratorIterator/RecursiveArrayIterator fait un dépassement de capacité mémoire. Je vais chercher et si je trouve une explication qui tienne la route je ferais un suivi ici
rawsrc est actuellement connecté   Envoyer un message privé Réponse avec citation 10
Vieux 14/02/2011, 08h41   #16
Futur Membre du Club
 
Damien
Inscription : juillet 2009
Messages : 50
Détails du profil
Informations personnelles :
Nom : Damien

Informations forums :
Inscription : juillet 2009
Messages : 50
Points : 16
Points : 16
Citation:
Bon comme je suis un sale entêté teigneux, j'ai continué à creuser et voici ce que je te propose.
J'admire ta ténacité fasse à un problème qui ne te concerne pas au premier abord

Citation:
J'ai quand même un peu honte car c'est désarmant de simplicité.
Bah oui et non, vu le soucis je me doutais qu'une résolution extrêmement simple existait, mais à côté de ça j'ai pas été foutu de la trouver

Citation:
Et là tu vas me dire comment n'y ai-je pas pensé plutôt et bien saches que je n'en sais rien, si c'est bon tu peux me noter et si cela foire tu pourras me fouetter, promis
20/20

Citation:
De mon côté je n'arrive pas à expliquer pourquoi un banal RecursiveIteratorIterator/RecursiveArrayIterator fait un dépassement de capacité mémoire. Je vais chercher et si je trouve une explication qui tienne la route je ferais un suivi ici
La réponse m'intéresse également, j'ai du mal à saisir le comportement exact de la syntaxe qu'on a utilisé. Pourtant, j'ai vu la même sur la doc. Au vue du résultat, ça donne l'impression qu'il boucle exponentiellement sur l'intégralité du tableau, c'est à dire que pour un array type

Code :
1
2
3
4
5
6
7
array(
    ['champ1'] => 'blabla',
    ['champ2'] => 'blabla',
    ['champ3'] => 'blabla',
    ['champ4'] => 'blabla',
    ['champ5'] => 'blabla'
);
Il va faire sa boucle dans ce style :

1e tour : champ1
2e tour : champ1, 3e tour : champ2
4e tour : champ1, 5e tour : champ2, 6e tour : champ3

Résultat 6 tours pour arriver au champ3.

Ce n'est qu'une hypothèse, mais ça expliquerait pourquoi avec 19 lignes de 5 champs + 4 lignes de 3 champs il arrive à faire un nombre de tour supérieur à 160000...
Peut-être la manière dont le script est agencer. Pourtant selon la doc, si j'ai bien compris, avec cette méthode il efface petit à petit ce sur quoi il a déjà bouclé (suis pas sûr de ça, mais y a une phrase dans la doc qui le fais présager, selon une traduction arbitraire de ma part ^^) donc le dépassement de mémoire ne devrait pas se produire...


Quoi qu'il en soit, ta dernière réponse correspond exactement à ce que j'essayais de mettre en place dès le début ^^ Je n'ai juste pas pensé à l'astuce du $current, et à l'array_merge...

S'il existe un vrai système de notation dans ce forum, j'te mets la note maximale immédiatement pour ta détermination et le résultat obtenu !!

Encore merci !!
WibiMaster est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 09h58.


 
 
 
 
Partenaires

Hébergement Web