par
titerm » 30 juin 2007, 14:32
Parfois, c'est pas si facile de déréférencer.
Regarde le code suivant :
<?php
// un tableau de démo
$tree['one']['two']['three'] = '__LEAF__';
// On affiche le contenu
echo "le tree de base =>",var_dump($tree);
// crée un pointer sur le tableau
$pointer = &$tree;
// parcour le tableau jusqu'a la premiere feuille
// Ca n'alter rien ca parcours, a la fin du while, echo $pointer retournerai __LEAF__
while(is_array($pointer)) {
$key = key($pointer);
echo "inwhile key = $key & \$tree=>", var_dump($tree);
$pointer = &$pointer[$key];
}
echo "before unset =>", var_dump($pointer,$tree);
unset($pointer);
echo "after unset =>", var_dump($pointer,$tree);
// copy le tableau
$copy = $tree;
// Modifie la feuille
$tree['one']['two']['three'] = 'ALTER';
// Affiche le tableau d'origine et la copy
echo "tree => ",var_dump($tree);
echo "copy => ",var_dump($copy);
et le résultat
Code : Tout sélectionner
le tree de base =>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = one & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = two & $tree=>array(1) {
["one"]=>
&array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = three & $tree=>array(1) {
["one"]=>
&array(1) {
["two"]=>
&array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
before unset =>string(8) "__LEAF__"
array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
&string(8) "__LEAF__"
}
}
}
after unset =>NULL
array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
tree => array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
copy => array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
On constate a la sortie du while que $tree contient 2 références... Je cherche encore pourquoi...
et après le unset, il n'en contient plus qu'une, mais c'est encore une de trop. Du coup, on ne peut toujour pas dupliquer $tree a la sortie.
Pour contourner ca, j'ai fais le code suivant. Je suis obliger de passer par une variable intermédiaire pour pouvoir faire un unset de $pointer avant de le mettre a jour... Super pratique...
<?php
// un tableau de démo
$tree['one']['two']['three'] = '__LEAF__';
// On affiche le contenu
echo "le tree de base =>",var_dump($tree);
// crée un pointer sur le tableau
$pointer = &$tree;
// parcour le tableau jusqu'a la premiere feuille
// Ca n'alter rien ca parcours, a la fin du while, echo $pointer retournerai __LEAF__
while(is_array($pointer)) {
$key = key($pointer);
echo "inwhile key = $key & \$tree=>", var_dump($tree);
// Utilise une var tampon
$pointer2 = &$pointer[$key];
// on supprime la référence
unset($pointer);
// On réafect a pointer
$pointer = $pointer2;
// On supprime la var tampon puisque c'est aussi une référence
unset($pointer2);
}
echo "before unset =>", var_dump($pointer,$tree);
unset($pointer);
echo "after unset =>", var_dump($pointer,$tree);
// copy le tableau
$copy = $tree;
// Modifie la feuille
$tree['one']['two']['three'] = 'ALTER';
// Affiche le tableau d'origine et la copy
echo "tree => ",var_dump($tree);
echo "copy => ",var_dump($copy);
Et la voila le résultat.
Code : Tout sélectionner
X-Powered-By: PHP/5.2.0
Content-type: text/html; charset=iso-8859-15
le tree de base =>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = one & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = two & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = three & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
before unset =>string(8) "__LEAF__"
array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
after unset =>NULL
array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
tree => array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
copy => array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
J'ai bien obtenu une copy de mon arbre...
Reste la question, pourquoi y avait il 2 références, d'autant que meme si l'arbre est plus profond, il n'y en a tjs que 2 qui glisse vers le fond...
Au final, j'ai une solution plus propre en utilisant la SPL, mais la conso ram n'est pas la meme et il faut que je vérifie si cela s'applique dans mon contexte (parcequeici, c'est une version simplifiée du problème

)
Le code avec la SPL
<?php
$tree = new ArrayObject(array('one'=>array('two'=>array('three'=>'LEAF'))));
var_dump($tree);
// crée pointer sur le tableau (c'est un objet donc passage par réf)
$pointer = $tree;
var_dump($tree,$pointer);
while(is_array(current($pointer))) {
$key = key($pointer);
$pointer = new ArrayObject($pointer->offsetGet($key));
echo "inwhile key = $key & \$tree=>", var_dump($pointer,$tree);
}
echo "before unset =>", var_dump($pointer,$tree);
unset($pointer);
echo "after unset =>", var_dump($pointer,$tree);
// Pour la copie, Au choix
// soit cette solution
$copy = $tree->getArrayCopy();
// ou
// $copy = clone $tree;
// Modifie la feuille
$tree['one']['two']['three'] = 'ALTER';
// Affiche le tableau d'origine et la copy
echo "tree => ",var_dump($tree);
echo "copy => ",var_dump($copy);
et le résultat
Code : Tout sélectionner
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
inwhile key = one & $tree=>object(ArrayObject)#2 (1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
inwhile key = two & $tree=>object(ArrayObject)#3 (1) {
["three"]=>
string(4) "LEAF"
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
before unset =>object(ArrayObject)#3 (1) {
["three"]=>
string(4) "LEAF"
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
after unset =>NULL
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
tree => object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
copy => object(ArrayObject)#3 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
Parfois, c'est pas si facile de déréférencer.
Regarde le code suivant :
[php]
<?php
// un tableau de démo
$tree['one']['two']['three'] = '__LEAF__';
// On affiche le contenu
echo "le tree de base =>",var_dump($tree);
// crée un pointer sur le tableau
$pointer = &$tree;
// parcour le tableau jusqu'a la premiere feuille
// Ca n'alter rien ca parcours, a la fin du while, echo $pointer retournerai __LEAF__
while(is_array($pointer)) {
$key = key($pointer);
echo "inwhile key = $key & \$tree=>", var_dump($tree);
$pointer = &$pointer[$key];
}
echo "before unset =>", var_dump($pointer,$tree);
unset($pointer);
echo "after unset =>", var_dump($pointer,$tree);
// copy le tableau
$copy = $tree;
// Modifie la feuille
$tree['one']['two']['three'] = 'ALTER';
// Affiche le tableau d'origine et la copy
echo "tree => ",var_dump($tree);
echo "copy => ",var_dump($copy); [/php]
et le résultat
[code]
le tree de base =>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = one & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = two & $tree=>array(1) {
["one"]=>
&array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = three & $tree=>array(1) {
["one"]=>
&array(1) {
["two"]=>
&array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
before unset =>string(8) "__LEAF__"
array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
&string(8) "__LEAF__"
}
}
}
after unset =>NULL
array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
tree => array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
copy => array(1) {
["one"]=>
array(1) {
["two"]=>
&array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
[/code]
On constate a la sortie du while que $tree contient 2 références... Je cherche encore pourquoi...
et après le unset, il n'en contient plus qu'une, mais c'est encore une de trop. Du coup, on ne peut toujour pas dupliquer $tree a la sortie.
Pour contourner ca, j'ai fais le code suivant. Je suis obliger de passer par une variable intermédiaire pour pouvoir faire un unset de $pointer avant de le mettre a jour... Super pratique...
[php]
<?php
// un tableau de démo
$tree['one']['two']['three'] = '__LEAF__';
// On affiche le contenu
echo "le tree de base =>",var_dump($tree);
// crée un pointer sur le tableau
$pointer = &$tree;
// parcour le tableau jusqu'a la premiere feuille
// Ca n'alter rien ca parcours, a la fin du while, echo $pointer retournerai __LEAF__
while(is_array($pointer)) {
$key = key($pointer);
echo "inwhile key = $key & \$tree=>", var_dump($tree);
// Utilise une var tampon
$pointer2 = &$pointer[$key];
// on supprime la référence
unset($pointer);
// On réafect a pointer
$pointer = $pointer2;
// On supprime la var tampon puisque c'est aussi une référence
unset($pointer2);
}
echo "before unset =>", var_dump($pointer,$tree);
unset($pointer);
echo "after unset =>", var_dump($pointer,$tree);
// copy le tableau
$copy = $tree;
// Modifie la feuille
$tree['one']['two']['three'] = 'ALTER';
// Affiche le tableau d'origine et la copy
echo "tree => ",var_dump($tree);
echo "copy => ",var_dump($copy); [/php]
Et la voila le résultat.
[code]
X-Powered-By: PHP/5.2.0
Content-type: text/html; charset=iso-8859-15
le tree de base =>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = one & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = two & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
inwhile key = three & $tree=>array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
before unset =>string(8) "__LEAF__"
array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
after unset =>NULL
array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
tree => array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
copy => array(1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(8) "__LEAF__"
}
}
}
[/code]
J'ai bien obtenu une copy de mon arbre...
Reste la question, pourquoi y avait il 2 références, d'autant que meme si l'arbre est plus profond, il n'y en a tjs que 2 qui glisse vers le fond...
Au final, j'ai une solution plus propre en utilisant la SPL, mais la conso ram n'est pas la meme et il faut que je vérifie si cela s'applique dans mon contexte (parcequeici, c'est une version simplifiée du problème :) )
Le code avec la SPL
[php]
<?php
$tree = new ArrayObject(array('one'=>array('two'=>array('three'=>'LEAF'))));
var_dump($tree);
// crée pointer sur le tableau (c'est un objet donc passage par réf)
$pointer = $tree;
var_dump($tree,$pointer);
while(is_array(current($pointer))) {
$key = key($pointer);
$pointer = new ArrayObject($pointer->offsetGet($key));
echo "inwhile key = $key & \$tree=>", var_dump($pointer,$tree);
}
echo "before unset =>", var_dump($pointer,$tree);
unset($pointer);
echo "after unset =>", var_dump($pointer,$tree);
// Pour la copie, Au choix
// soit cette solution
$copy = $tree->getArrayCopy();
// ou
// $copy = clone $tree;
// Modifie la feuille
$tree['one']['two']['three'] = 'ALTER';
// Affiche le tableau d'origine et la copy
echo "tree => ",var_dump($tree);
echo "copy => ",var_dump($copy); [/php]
et le résultat
[code]
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
inwhile key = one & $tree=>object(ArrayObject)#2 (1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
inwhile key = two & $tree=>object(ArrayObject)#3 (1) {
["three"]=>
string(4) "LEAF"
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
before unset =>object(ArrayObject)#3 (1) {
["three"]=>
string(4) "LEAF"
}
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
after unset =>NULL
object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
tree => object(ArrayObject)#1 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(5) "ALTER"
}
}
}
copy => object(ArrayObject)#3 (1) {
["one"]=>
array(1) {
["two"]=>
array(1) {
["three"]=>
string(4) "LEAF"
}
}
}
[/code]