php引用传值问题
$arr = [];$str = "傻逼";
$treeArr = &$arr;
for($i=0; $i < 2; $i++) {
$word = mb_substr($str,$i,1);
$treeArr = &$treeArr[$word] ?? $treeArr = false;
}
print_r($arr);
请大佬解答一下为什么会得到如下结果?没看太明白,感谢
回答
如果你使用一些 IDE ,就会提示你 Only variables can be passed by reference
,译为:只能通过引用传递变量。
foreach (range('A', 'B') as $i) { $b = &$b[$i] ? $b[$i] : $b = false;
}
使用快速修复,IDE 会将你的代码修复为
foreach (range('A', 'B') as $i) { $f = $b[$i] ? $b[$i] : $b = false;
$b = &$f;
}
再参考文档中的内容。
以下内容可以通过引用传递:
- 变量,例如
foo($a)
- New 语句,例如
foo(new foobar())
- 从函数中返回的引用.
任何其它表达式都不能通过引用传递,结果未定义。
简单来说,这就是一种错误使用,类似的还有:
sort(explode('','Hello'));
array_push(['A'],['B']);
这些都会引起这个错误。
如果你以为我只是说到这里,那不就偏题了。
因为引用不能对表达式起作用,所以现在的代码实际上就等同于下面的代码。(错误的例子,下面有详细,正确的)
foreach (range('A', 'B') as $i) { $b = &$b[$i];
$b = false;
}
补充内容
补充:这里的代码转换有些唐突,可能有些难以理解,下面使用 php-parser 解析一下代码
use PhpParser\Error;use PhpParser\NodeDumper;
use PhpParser\ParserFactory;
// 这里包含的是代码
$code = file_get_contents('ref.php');
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try {
$ast = $parser->parse($code);
} catch (Error $error) {
echo "Parse error: {$error->getMessage()}\n";
return;
}
$dumper = new NodeDumper;
echo $dumper->dump($ast) . "\n";
使用 php-parser 打印语法树。
... stmts: array(
0: Stmt_Expression(
expr: Expr_Ternary(
cond: Expr_AssignRef(
var: Expr_Variable(
name: b
)
expr: Expr_ArrayDimFetch(
var: Expr_Variable(
name: b
)
dim: Expr_Variable(
name: i
)
)
)
if: Expr_ArrayDimFetch(
var: Expr_Variable(
name: b
)
dim: Expr_Variable(
name: i
)
)
else: Expr_Assign(
var: Expr_Variable(
name: b
)
expr: Expr_ConstFetch(
name: Name(
parts: array(
0: false
)
)
)
)
)
)
)
...
可以看到,虽然三元运算符的优先级高于 =
符号,但是因为引用不能引用表达式,所以在语法阶段就被拆分开来了,也就是说,实际运行时是下面这样的。
foreach (range('A', 'B') as $i) { ($b = &$b[$i]) ? $b[$i] : $b = false;
}
补充内容结束
查询手册可知,引用符号的优先级高于三元运算符。
所以 $b = &$b[$i]
,就会被赋值 $b
。
这时候 $b[$i]
肯定是不存在的,但是又根据手册可知,当引用一个不存在的变量时,php 将会自动初始化这个变量。
现在运行代码,第一次循环时,运行如下。=
的运算优先级低于 &
所以这时候 $b
就被重新引用给了 $a['A']
就变成了初始化后的 null
。
因为 $a['A']
是不存在的,刚被初始化,所以就是 null ,这时候就要执行三元运算符中 false
的部分 ,即 $b
又被赋给了 false
,所以这时候,$a['A'] = null
也就等于了 false
,现在 $b
引用着的就是 $a['A']
。
现在运行第二遍,现在 $b
已经被引用给了 $a['A']
,所以现在循环出来的 $i = B
的,就成了初始化 $a['A']['B']
了,因为一开始初始化是 null
,看断点中的 $b
值是 null
,但是紧接着又赋值了 false
😃 好了,就是这样。
以上是 php引用传值问题 的全部内容, 来源链接: utcz.com/a/61955.html