1

わかりました、私は本当にこれで立ち往生しています。あなたが私を助けてくれることを願っています。

階層データの管理に使用されるクラスがあります。入力は、次の構造を持つ単純な配列です(単なる例)。

$list = array(
(object) array('id' => 1, 'nombre' => 'Cámaras de fotos', 'parentId' => null),
(object) array('id' => 2, 'nombre' => 'Lentes', 'parentId' => null),
(object) array('id' => 3, 'nombre' => 'Zoom', 'parentId' => 2),
(object) array('id' => 4, 'nombre' => 'SLR', 'parentId' => 1),
(object) array('id' => 5, 'nombre' => 'Primarios', 'parentId' => 2),
(object) array('id' => 6, 'nombre' => 'Sensor APS-C', 'parentId' => 4),
(object) array('id' => 7, 'nombre' => 'Full-frame', 'parentId' => 4),
(object) array('id' => 8, 'nombre' => 'Flashes', 'parentId' => null),
(object) array('id' => 9, 'nombre' => 'Compactas', 'parentId' => 1)
);

この方法でクラスにデータを入力します。

$Hierarchical = new Hierarchical;
$Hierarchical->plain = $list;

createTree次に、リストの多次元配列表現を作成するためのパブリック関数( )があります。それは完璧に動作します。結果を返すか、内部に保存できます$this->tree

ご覧のとおり、これは非常に簡単です。iterateTree再帰関数であるprivate関数を呼び出します。

class Hierarchical {

    public $plain = array();
    public $tree = array();

    public function createTree($parentId=0, $return=false) {

    $tree = $this->iterateTree($parentId);

    if(!$return) {
        $this->tree = $tree;
    } else {
        return $tree;
    }

    }


    private function iterateTree($parentId) {

    $resArray = array();

    foreach($this->plain as $item) {

        if($item->parentId == $parentId) {

            $children = $this->iterateTree($item->id);

            if( count($children) > 0 ) {
                $item->children = $children;
            }

            $resArray[] = $item;

        }

    }

    return $resArray;

    } 

}

ここまでは順調ですね。正常に動作します。

しかし...$this->plain呼び出した後に使用したいときに問題が発生しますcreateTree()。元のデータセットを返す代わりに、すべての子が追加された元の入力間のある種の混合を返します(と同様$this->tree)。

内容が変更されている理由がわかりません$this->plain。使用されている両方の関数でも、内容が変更されています。

foreachの後にforeach、元の配列を引数として渡し、$this->plain再帰関数内ではまったく使用せずに、内の変数の設定を解除しようとしました。何も機能しませんでした。

また、クラス内で値を変更する可能性のある他の関数も使用していません。

完全なミステリーです!

4

3 に答える 3

1

foreachループ内に$itemは配列内のオブジェクトへの参照があるため、行内の同じオブジェクトを変更します

$item->children = $children;

これは、元の配列$listとで参照されているオブジェクトに影響します$this->plain

$item1つの解決策は、foreachループ内でクローンを作成することです。

于 2012-05-23T23:29:20.360 に答える
1

ダグの答えによると、正しい関数は次のとおりです:(追加$itemAux = clone $item

private function iterateTree($parentId) {

    $resArray = array();

    foreach($this->plain as $item) {

        $itemAux = clone $item;

        if($itemAux->parentId == $parentId) {

            $children = $this->iterateTree($itemAux->id);

            if( count($children) > 0 ) {
                $itemAux->children = $children;
            }

            $resArray[] = $itemAux;

        }

    }

    return $resArray;

} 
于 2012-05-24T22:56:58.160 に答える
0

Dougの答えに追加すると、マニュアルには「オブジェクトは参照によって渡されない」(http://www.php.net/manual/en/language.oop5.references.php)と記載されていますが、代わりに考えると役立つ場合があります。オブジェクトは、それらを「含む」可能性のある変数から完全に分離されたエンティティとして、実際には参照によってどこにでも渡されます。

class testClass
{
    public $var1 = 1;
}

function testFunc($obj)
{
    $obj->var1 = 2;
}


$t = new testClass;
testFunc($t);
echo $t->var1; // 2

したがって、そうすると、実際には、その配列$item->children = $children;内の元の各オブジェクトに影響を及ぼします。$plain

于 2012-05-24T00:02:34.180 に答える