我创建了一个简单的类来管理一个看起来很奇怪的树数据结构(要遵循的代码)。当我发现这不是我的错误时,我创建了一个同样令人费解的行为的测试用例。这与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);
现在我预期的输出是看$ 1增量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
)
)
)
)
)
)
)
)
这仍然不是我追求的行为,但它更接近。我需要的是使用一串对象来遍历树(与第一种情况一样),一个指向值$ 2和$ 3的指针,在实际情况下是数组而不是交换。我不想做的是不必要地复制对象。
另一方面,我需要让所有对象共享一对他们都使用的变量。
我的猜测是,方法get()
可以提供byval
而不是byref
,尽管本能地这似乎是错误的。
任何人都可以解释$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
在堆栈中关闭。
答案 0 :(得分:1)
如果我理解你对此感到困惑(并且我认为我做了),你会遇到pre- and 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);
通过后增量,$this->one
的初始值将在所有后续迭代中进行。
作为旁注,我认为你不必担心在这里通过引用返回,因为PHP5中的所有对象都是通过引用传递的。