变量变量与 ++ 运算符如何配合工作?

7

给定一个数组(例如:$a = [2,3,3,1,5,2]),找到第一个重复的值。在这种情况下,即值为3,索引为2。

第二个重复的值将是2,因为索引更高(5)。

我在网上找到的一个解决方案:

function firstDuplicate($a) {
    foreach ($a as $v)
        if ($$v++) return $v;
        return -1;
}

$$v++是如何工作的?

$$v在第一次循环时等于$2,在第二次循环时等于$3,以此类推。

++如何应用于这个上下文中?感谢!

后续编辑:$$v++ 何时返回true?


firstDuplicate([-1, -1]) 然后炸药爆炸了。哨兵值太糟糕了。 - Alexander
2个回答

9
这里有两个要点。代码写得相当有趣,尽管理解起来很复杂。
第一点:变量变量 如您所理解的那样,在每次交互中,$$v 将分别转换为变量,即 $2、$3、$3、$1、$5、$2
PHP 非常灵活(甚至可能过于灵活),因此可以测试 if ($2),即使明显没有实例化 $2。它假定其值为 NULL,因此 if 检查未能通过。

*“注意:未定义变量:$2”将在日志中被抛出,但这不会 “破坏” 代码或阻止其执行。

第二点:递增 / 递减运算符++
了解前置和后置递增之间的区别非常重要。
$a = 0;
$b = 0;

($a++ === 1) // FALSE
(++$b === 1) // TRUE

预增量操作会先加上变量的值并返回(新的、加了之后的)结果;而后增量操作会先返回变量当前的值,然后再加上一。

结合使用

为了更易读懂,让我们翻译下面这行代码。

if ($$v++) return $v;

转换为

if ($$v) {
    return $v;
}
$$v = $$v + 1;

作为实际正在发生的事情,这是我们真正需要做的。
跳到第二次迭代(数组中的第一个3,其中$v = 3),我们会有:
// Right now $3 doesn't exist, so it's value is NULL
if ($3) { // "if (NULL)", so it's FALSE
    return 3;
}
$3 = $3 + 1; // "NULL + 1"
// $3 === 1 at this point

为什么 PHP 编译 NULL + 1 = 1 是另一个完全不同的话题(“太灵活”了,记得吗?)。底线是假设 NULL数字值0,因此解析为 0 + 1 = 1

现在当涉及到第三次迭代(数组中的第二个3,其中$v = 3,但这一次变量$3存在且其值为1)。

// Right now: $3 === 1
if ($3) { // TRUE
    return 3;
}
$3 = $3 + 1; // This line is never reached, the code has "returned" already

所以,这就是全部了,希望它相对容易理解。这是许多不同的部分,必须结合起来才能有意义。


谢谢,这是一个清晰的解释。正是我所寻找的。现在我明白了。 - Tiberiu
“所以即使$2从未被实例化,当你测试if ($2)时它也不会抱怨。” 它肯定会抛出未定义的通知吧? - James
1
好的观点@James,我更新了答案。我的意思是“它不会破坏代码”,但说“它不会抱怨”确实是错误的。 - mathielo
@mathielo,你会使用这个解决方案(带有通知)还是采用另一种(稍微长一点)的方式,比如使用一个临时数组(由$a中的唯一值组成)与$a进行比较并获取差异? - Tiberiu
@user3274898 可以通过首先检查变量是否存在来避免通知:if (!isset($$v)) $$v = 0;(遵循答案的一行解决方案风格),因此无需使用临时数组 :) - mathielo

3

$$ 是 PHP 中“可变变量”的一部分,它是 PHP 中功能强大但常常被误用的特性之一。

在您的情况下,使用 $a = [2,3,3,1,5,2]

function firstDuplicate($a) {
    foreach ($a as $v)
        if ($$v++) return $v;
    return -1;
}

$$v 相当于变量 $3,其值为未定义。

然后 $3++ 将创建一个值为 0 的变量 $3,并且 if 语句的条件将为 false。

当再次调用 $3++(找到重复项时),它的值将为 1,这使得 if 语句通过,return $v; 将返回第一个重复项(即 $v 的值)来终止函数。

注意: 0 等同于 False,而每个非零值被视为 True


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接