2019 年 10 月,Python 3.8 引入了 Walrus 运算符(:=) 通过 PEP 572 ——从而引发了编程语言历史上最大的争议之一。这场争论非常激烈,以至于 Python 的发明者 吉多·范罗苏姆 2018 年 7 月——甚至在发布之前——他作为 BDFL 的职位(终身仁慈独裁者)。自 2019 年初以来,Python 转而由选举产生的指导委员会管理。
if (n := len(items)) > 10:
print(f"List is too long ({n} elements)")
治理分歧在海象讨论之后立即出现——这是一个罕见的案例,单个语言特性竟然会造成结构性后果。范罗苏姆在声明中解释道:“压垮骆驼的最后一根稻草是一项极具争议的 Python 增强提案。在我接受它之后,人们在 Twitter 等社交媒体上发表了一些伤害我个人的言论。”
他继续说道:“如今 PEP 572 已经结束,我再也不想为了 PEP 而如此费力地奋斗,却发现这么多人厌恶我的决定。我想彻底退出决策过程。” 批评不仅来自更广泛的社区,也来自核心开发人员。
他们认为,该运算符违背了“Python 之禅”的基本 Python 原则——尤其是“追求简洁而非复杂”的理念。Python 作为无可争议的语言设计者,在近三十年的发展历程中,这标志着一个时代的终结。然而,尽管 Python 不得不引入新的海象运算符,并因此导致其社区分裂,但问题也随之而来:其他语言如何处理类似的概念?
Python 运算符 := (赋值表达式别名“Walrus”)在 PHP 中不存在——因为不需要。在 PHP 中,赋值运算符 = 总是 同时声明和表达: 赋值操作返回被赋值的值。这正是“赋值并测试”等惯用模式在 if-没有自己的语言特征的条件。
function get_some_field() {
return 'foo';
}
if ($a = get_some_field()) {
echo $a; // foo
}
// Hinweis: $a ist *gesetzt*, selbst wenn die Bedingung falsy wäre.
$a = get_some_field() 赋值并计算到右侧。如果这是“真”,则输入 if-Block。背景:在 Python 中, := (PEP 572) 因为简单赋值不是表达式。在 PHP 中,情况一直不同,所以没有等效的需求。有两件事经常会导致 bug。: = (赋值)的优先级比大多数关系运算符低;括号决定评估结果。
在更复杂的表达式中,您应该始终使用括号来提高可读性和清晰度。 ?? 有其自身的、相当低的优先级。这解释了以下表达式中的意外情况: $x ?? null === null. 不带括号,首先 null === null 评估。最好始终明确地将: ($x ?? null) === null. $a 也存在于 if-Blocks – 可能具有虚假值。
function get_some_field() {
return 'bar';
}
if ( ($a = get_some_field()) === 'bar' ) {
echo $a; // bar
}
所以很明显 === 'bar' 应用于赋值。括号在这里非常重要,因为它可以提高可读性和优先级。在实践中,这种模式通过存储查询结果并进行检查,避免了不必要的重复调用(例如,查询构建器的调用)。在生产环境中,例如基于 Laravel 的项目,可以更频繁地观察到以下模式。:
if ( ($foo = Foo::where('foo', 'bar')) && $foo->count() > 0 ) {
dd($foo->get());
}
&& 是短路:只有当左侧部分为真时,右侧部分才会被求值。通过在上游赋值语句,可以避免在 if 语句之外赋值语句。这是否是一个好的做法取决于你团队的代码和分析工具;从语义上讲,这是正确的。至少,你应该知道在实际遇到代码时会做什么。
PHP 不需要“海象运算符”,因为赋值本身就是表达式。这使得像“赋值并测试”这样的惯用模式成为可能——高效且简洁。与此同时,对规范的要求也随之提高:括号、严格比较、对真/假的认知以及清晰的团队约定都是强制性的。遵循这些准则的人无需额外的语言特性即可享受海象理念带来的好处。