1

奇妙な動作をしているように見えるツリー データ構造を管理するための単純なクラスを作成しました (以下のコード)。これが私の間違いではないことが明らかになったとき、私は同様に不可解な動作を生成するテスト ケースを作成しました。これは 5.3 と 5.4 で同じです。

これは私のテストケースです:

<?php
class testcaseA {
    public function __construct($one=0, $two=1, $three=2) {
        $this->obj = new testcaseB($one++, $three, $two);
    }
    public function &get($what){
        return $this->obj->get($what);
    } 
}
class testcaseB {
    public function __construct($one, &$two, &$three) {
        $this->one=$one;
        $this->two=$two;
        $this->three=$three;
        echo "\$one={$one}";
    }
    public function &get($what){
        echo "<p>You asked for $what. $what ain't no country I ever heard of.<br />";
        echo "Check: [{$this->one}], {$this->two}, {$this->three}. Is this thing on?</p>";
        $this->obj[$what] = new testcaseB($this->one++,$this->two,$this->three);
        return $this->obj[$what];
    } 
}
ini_set('display_errors',1); 
error_reporting(E_ALL);
$bob = new testcaseA();
$bob->get("What")->get("Spam")->get("America");
$bob->get("What")->get("EU")->get("France");
echo "<pre>";
print_r($bob);

これで、$one の値が 1,2,3,1,2,3 ずつ増加し、ツリーの形が生成されると期待した出力が得られました。

これは私が実際に得た出力です:

$one=0

You asked for What. What ain't no country I ever heard of.
Check: [0], 2, 1. Is this thing on?
$one=0

You asked for Spam. Spam ain't no country I ever heard of.
Check: [0], 2, 1. Is this thing on?
$one=0

You asked for America. America ain't no country I ever heard of.
Check: [0], 2, 1. Is this thing on?
$one=0

You asked for What. What ain't no country I ever heard of.
Check: [1], 2, 1. Is this thing on?
$one=1

You asked for EU. EU ain't no country I ever heard of.
Check: [1], 2, 1. Is this thing on?
$one=1

You asked for France. France ain't no country I ever heard of.
Check: [1], 2, 1. Is this thing on?
$one=1

testcaseA Object
(
    [obj] => testcaseB Object
        (
            [one] => 2
            [two] => 2
            [three] => 1
            [obj] => Array
                (
                    [What] => testcaseB Object
                        (
                            [one] => 2
                            [two] => 2
                            [three] => 1
                            [obj] => Array
                                (
                                    [EU] => testcaseB Object
                                        (
                                            [one] => 2
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [France] => testcaseB Object
                                                        (
                                                            [one] => 1
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

最初はこれに戸惑いましたが、チェーンの使用法が予期しない方法で値を設定しているのではないかと思いました。

だから私は前のコードの後に​​追加したこれを試しました:

...same classes and initial code as before...
$a=$bob->get("What");
$b=$a->get("Spam");
$c=$b->get("America");
//$bob->get("What")
$d=$a->get("EU");
$e=$d->get("France");  
print_r($bob);

これにより、異なるが、まだ予測できない一連の結果が生成されました。

You asked for What. What ain't no country I ever heard of.
Check: [2], 2, 1. Is this thing on?
$one=2

You asked for Spam. Spam ain't no country I ever heard of.
Check: [2], 2, 1. Is this thing on?
$one=2

You asked for America. America ain't no country I ever heard of.
Check: [2], 2, 1. Is this thing on?
$one=2

You asked for EU. EU ain't no country I ever heard of.
Check: [3], 2, 1. Is this thing on?
$one=3

You asked for France. France ain't no country I ever heard of.
Check: [3], 2, 1. Is this thing on?
$one=3testcaseA Object
(
    [obj] => testcaseB Object
        (
            [one] => 3
            [two] => 2
            [three] => 1
            [obj] => Array
                (
                    [What] => testcaseB Object
                        (
                            [one] => 4
                            [two] => 2
                            [three] => 1
                            [obj] => Array
                                (
                                    [Spam] => testcaseB Object
                                        (
                                            [one] => 3
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [America] => testcaseB Object
                                                        (
                                                            [one] => 2
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                    [EU] => testcaseB Object
                                        (
                                            [one] => 4
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [France] => testcaseB Object
                                                        (
                                                            [one] => 3
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

これはまだ私が求めている動作ではありませんが、より近いものです。必要なのは、オブジェクトのチェーンを使用してツリーをトラバースすることです (最初のケースと同様)。値 $two および $three へのポインターであり、実際のケースでは配列であり、交換されません。私がやりたくないのは、オブジェクトを不必要にコピーすることです。

一方で、すべてのオブジェクトが単一の変数ペアを共有する必要があります。

私の推測では、本能的にこれは間違っているように見えますが、この方法get()には余裕があるのではないでしょうか。byvalbyref

$one値が何をしているのか誰でも説明できますか?

また、最初のテストケースの動作、特に配列内の値を初めて理解するのを手伝ってくれる人はいますか?

アップデート

すばらしい提案を利用すると、テスト ケースは次のようになります。

class testcaseA {
    public function __construct($one=0, $two=1, $three=2) {
        $this->obj = new testcaseB(++$one, $three, $two);
    }
    public function &get($what){
        return $this->obj->get($what);
    } 
}
class testcaseB {
    public function __construct($one, &$two, &$three) {
        $this->one=$one;
        $this->two=$two;
        $this->three=$three;
        echo "[New:\$one={$one}]:";
    }
    //public function &get($what){
    public function &get($what){
        //echo "<p>You asked for $what. $what ain't no country I ever heard of.<br />";
        echo "Get:{$what}:[{$this->one}]<br />";
        if(!isset($this->obj[$what])){
            $this->obj[$what] = new testcaseB(++$this->one,$this->two,$this->three);
        }
        return $this->obj[$what];
    } 
}
echo "STARTING:<br />";
ini_set('display_errors',1); 
error_reporting(E_ALL);
echo "REALLY STARTING:<br />";
echo "<pre>";
echo "<p>One at a time:</p>";
$bob = new testcaseA();
$a=$bob->get("What");
$b=$a->get("Spam");
$c=$b->get("America");
$d=$a->get("EU");
$e=$d->get("France"); 
echo "<br />";
print_r($bob); 
echo "<p>Chained:</p>";
$bobby = new testcaseA();
$bobby->get("What")->get("Spam")->get("America");
$bobby->get("What")->get("EU")->get("France");
echo "<br />";
print_r($bob);

その出力は次のとおりです。

STARTING:
REALLY STARTING:

One at a time:
[New:$one=1]:Get:What:[1]
[New:$one=2]:Get:Spam:[2]
[New:$one=3]:Get:America:[3]
[New:$one=4]:Get:EU:[3]
[New:$one=4]:Get:France:[4]
[New:$one=5]:
testcaseA Object
(
    [obj] => testcaseB Object
        (
            [one] => 2
            [two] => 2
            [three] => 1
            [obj] => Array
                (
                    [What] => testcaseB Object
                        (
                            [one] => 4
                            [two] => 2
                            [three] => 1
                            [obj] => Array
                                (
                                    [Spam] => testcaseB Object
                                        (
                                            [one] => 4
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [America] => testcaseB Object
                                                        (
                                                            [one] => 4
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                    [EU] => testcaseB Object
                                        (
                                            [one] => 5
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [France] => testcaseB Object
                                                        (
                                                            [one] => 5
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

Chained:
[New:$one=1]:Get:What:[1]
[New:$one=2]:Get:Spam:[2]
[New:$one=3]:Get:America:[3]
[New:$one=4]:Get:What:[2]
Get:EU:[3]
[New:$one=4]:Get:France:[4]
[New:$one=5]:
testcaseA Object
(
    [obj] => testcaseB Object
        (
            [one] => 2
            [two] => 2
            [three] => 1
            [obj] => Array
                (
                    [What] => testcaseB Object
                        (
                            [one] => 4
                            [two] => 2
                            [three] => 1
                            [obj] => Array
                                (
                                    [Spam] => testcaseB Object
                                        (
                                            [one] => 4
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [America] => testcaseB Object
                                                        (
                                                            [one] => 4
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                    [EU] => testcaseB Object
                                        (
                                            [one] => 5
                                            [two] => 2
                                            [three] => 1
                                            [obj] => Array
                                                (
                                                    [France] => testcaseB Object
                                                        (
                                                            [one] => 5
                                                            [two] => 2
                                                            [three] => 1
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

出力数値は正しいように見えますが$one、スタック内でオフになっています。

4

1 に答える 1

1

あなたが何について混乱しているのかを理解していれば (そして私は理解していると思います)、 pre-increment と post-incrementの微妙な違いに遭遇したことになります。これは、コードで最も簡単に示すことができます。

$a = 1;
echo $a++; // 1
echo $a;   // 2

一方で:

$a = 1;
echo ++$a; // 2
echo $a;   // 2

基本的に、インクリメントする値の++ に配置することで、新しい値を取得します。(行ったように)後に配置すると、古い値が得られます。

あなたのコードの重要な行はこれだと思います:

$this->obj[$what] = new testcaseB($this->one++,$this->two,$this->three);

...次のようになります。

$this->obj[$what] = new testcaseB(++$this->one,$this->two,$this->three);

post-increment を使用すると、 の初期値が$this->one後続のすべての反復に適用されます。

ちなみに、ここで参照渡しについて心配する必要はないと思います。とにかく、PHP5 のすべてのオブジェクトは参照渡しです。

于 2012-07-03T15:00:35.827 に答える