Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP5:ReturnByRef方法产生意外结果_Php_Testing_Pointers_Byref - Fatal编程技术网

PHP5:ReturnByRef方法产生意外结果

PHP5:ReturnByRef方法产生意外结果,php,testing,pointers,byref,Php,Testing,Pointers,Byref,我创建了一个简单的类来管理一个树数据结构,它的行为似乎很奇怪(下面的代码)。当这显然不是我的错误时,我创建了一个测试用例,它产生了同样令人费解的行为。这在5.3和5.4中是相同的 这是我的测试用例: <?php class testcaseA { public function __construct($one=0, $two=1, $three=2) { $this->obj = new testcaseB($one++, $three, $two);

我创建了一个简单的类来管理一个树数据结构,它的行为似乎很奇怪(下面的代码)。当这显然不是我的错误时,我创建了一个测试用例,它产生了同样令人费解的行为。这在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);
这一点一开始让我感到困惑,但我想知道,这种链式用法是否以我不期望的方式设置了值

因此,我尝试了在前面的代码之后添加的:

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
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)
这产生了一系列不同但仍不可预测的结果

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);
这仍然不是我所追求的行为,但它更接近。我需要的是使用一个对象链来遍历树(与第一种情况一样),一个指向$2和$3的指针,在实际情况下,它们是数组,不交换。我不想做的是不必要地复制对象

另一方面,我确实需要让所有对象共享一对它们都使用的变量

我的猜测是,方法
get()
可以是
byval
而不是
byref
,尽管本能上这似乎是错误的

有人能解释一下
$one
值在做什么吗

还有谁能帮助我理解第一个测试用例的行为,特别是第一次对数组中的值的行为

更新

利用令人敬畏的建议,我们的测试用例现在看起来像:

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
已关闭

如果我理解你的困惑(我想我也理解),你就会发现两者之间的细微差别。这可以很容易地在代码中演示:

$this->obj[$what] = new testcaseB($this->one++,$this->two,$this->three);
另一方面:

$this->obj[$what] = new testcaseB(++$this->one,$this->two,$this->three);
基本上,通过将
++
放在您增加的值之前,您将获得新值。通过将其放在后面(如您所做的),您将获得旧值

我认为您代码中的关键行是:

…应该是这样的:

使用post增量,
$this->one
的初始值将通过所有后续迭代进行


作为旁注,我认为您不必担心在这里通过引用返回,因为PHP5中的所有对象都是通过引用传递的。

如果我理解您的困惑(我想我也理解),那么您已经遇到了它们之间的微妙区别。这可以很容易地在代码中演示:

$this->obj[$what] = new testcaseB($this->one++,$this->two,$this->three);
另一方面:

$this->obj[$what] = new testcaseB(++$this->one,$this->two,$this->three);
基本上,通过将
++
放在您增加的值之前,您将获得新值。通过将其放在后面(如您所做的),您将获得旧值

我认为您代码中的关键行是:

…应该是这样的:

使用post增量,
$this->one
的初始值将通过所有后续迭代进行


顺便说一句,我认为您不必担心在这里通过引用返回,因为PHP5中的所有对象都是通过引用传递的。

有趣的是,当get成为一个普通的byval函数时,我没有得到预期的行为。运行这两个版本(一个接一个和chain)在另一个顺序中,仍然有链对对象堆栈做了不好的事情。是的,$I++和+++$I不一样,这是我现在接受的教育。有趣的是,当get变成一个普通的byval函数时,我没有得到预期的行为。以另一个顺序运行两个版本(一个接一个和chain)仍然会让chain对对象堆栈做坏事。是的,$I++和+++$I不一样,这就是为什么这些值有自己的作用。我以后一定会小心的。让我真正感到困惑的是$bob不是一棵树-“垃圾邮件”和“美国”首先不见了。@MatthewBrown好的,让我再看一眼。太棒了,谢谢。在我最初的(非平凡的示例)中,
$this->value
似乎不存在于名为
&get($child)
的方法中,但在所有其他位置都可用。$one++只是用来表示这一点(令人尴尬的是,我忽略了一个细微的差别)。@MatthewBrown好的,我明白了。问题行实际上与我上面提到的相同。因为在创建新对象之前没有检查
$this->obj[$what]
是否已经存在,所以您正在覆盖上一次迭代中的实例。要解决此问题,只需在行前面加上
if(!isset($this->obj[$what])
。PS我喜欢名为
$bob
的变量,这也有助于解释测试用例的行为。然而:
$bobby->get(“什么”)->get(“垃圾邮件”)->get(“美国”)
$bobby->get(“什么”)->get(“欧盟”)->get(“法国”)get(“What”)
时,code>生成1和3。这并不是说你的答案不正确,只是因为我的测试用例是垃圾。这就解释了价值观在做自己的事情。我以后一定会小心的。让我真正感到困惑的是$bob不是一棵树-“垃圾邮件”和“美国”首先不见了。@MatthewBrown好的,让我再看一眼。太棒了,谢谢。在我最初的(非平凡的示例)中,
$this->value
似乎不存在于名为
&get($child)
的方法中,但在所有其他位置都可用。$one++只是用来表示这一点(令人尴尬的是,我忽略了一个细微的差别)。@MatthewBrown好的,我明白了。问题行实际上与我上面提到的相同。因为在创建新对象之前没有检查
$this->obj[$what]
是否已经存在,所以您正在覆盖上一次迭代中的实例。要解决此问题,只需在行前面加上
if(!isset($this->obj[$what])
。PS我喜欢名字像
$bob
的变量,这也有助于解释
$this->obj[$what] = new testcaseB($this->one++,$this->two,$this->three);
$this->obj[$what] = new testcaseB(++$this->one,$this->two,$this->three);