php引用传值问题

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);

请大佬解答一下为什么会得到如下结果?没看太明白,感谢
php引用传值问题

回答

如果你使用一些 IDE ,就会提示你 Only variables can be passed by reference,译为:只能通过引用传递变量。

php引用传值问题

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())

  • 从函数中返回的引用.

任何其它表达式都不能通过引用传递,结果未定义。

php引用传值问题

简单来说,这就是一种错误使用,类似的还有:

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 打印语法树。

php引用传值问题

...

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;

}

补充内容结束

查询手册可知,引用符号的优先级高于三元运算符。
php引用传值问题

所以 $b = &$b[$i],就会被赋值 $b

这时候 $b[$i] 肯定是不存在的,但是又根据手册可知,当引用一个不存在的变量时,php 将会自动初始化这个变量。

php引用传值问题
现在运行代码,第一次循环时,运行如下。
= 的运算优先级低于 & 所以这时候 $b就被重新引用给了 $a['A'] 就变成了初始化后的 null

因为 $a['A'] 是不存在的,刚被初始化,所以就是 null ,这时候就要执行三元运算符中 false 的部分 ,即 $b 又被赋给了 false ,所以这时候,$a['A'] = null 也就等于了 false,现在 $b 引用着的就是 $a['A']

php引用传值问题

现在运行第二遍,现在 $b 已经被引用给了 $a['A'] ,所以现在循环出来的 $i = B 的,就成了初始化 $a['A']['B'] 了,因为一开始初始化是 null ,看断点中的 $b 值是 null ,但是紧接着又赋值了 false

php引用传值问题

😃 好了,就是这样。

以上是 php引用传值问题 的全部内容, 来源链接: utcz.com/a/61955.html

回到顶部