<?php
if ($a = 100 && $b = 200) {
var_dump($a, $b);
}
// 輸出什麼?
乍看之下,依優先級 && 高於 =,應為 $a = (100 && $b) = 200,但實際輸出為 bool(true) int(200)。這違背直覺,源於 PHP 獨特的語法解析設計。
PHP 官方手冊註明:
Although = has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.
這意味著 PHP 讓賦值運算子 = 在特定情境下「讓步」給 &&、||,使右側賦值先結合。這在 C/C++ 中屬語法錯誤,PHP 保留此行為係為歷史相容性。
PHP 核心語法定義(簡化)中,expr_without_variable 規則讓 T_BOOLEAN_AND 表現如一元運算子:
expr_without_variable:
| expr T_BOOLEAN_AND { zend_do_boolean_and_begin(&$1, &$2); } expr
此設計消除 = 與 && 的歸約衝突,導致 $b = 200 先於 && 結合。
PHP 另提供 and(T_LOGICAL_AND)、or(T_LOGICAL_OR),優先級**低於** =,可寫出經典防禦性程式碼:
$result = mysql_query($sql) or die(mysql_error());
// 等價於
if (!$result = mysql_query($sql)) {
die(mysql_error());
}
甚至可模擬三元運算子:
$person = $who or $person = "default";
// 等價於
$person = empty($who) ? "default" : $who;
| 結合方向 | 運算子 |
|---|---|
| 左 | , |
| 左 | or |
| 左 | xor |
| 左 | and |
| 右 | |
| 右 | = += -= *= /= .= %= &= |= ^= ~=<<= >>= |
| 左 | ? : |
| 左 | || |
| 左 | && |
| 左 | | |
| 左 | ^ |
| 左 | & |
| 無 | == != === !== |
| 無 | < <= > >= |
| 左 | << >> |
| 左 | + - . |
| 左 | * / % |
| 右 | ! ~ ++ -- (int) (float) (string) (array) (object) @ |
| 右 | [ |
| 無 | new |
() 消除歧義,如 if (($a = 100) && ($b = 200))。and/or:流程控制、錯誤處理場合優先考慮低優先級邏輯運算子。PHP 運算子優先級的特例設計源於歷史包袱,理解其底層語法規則有助於寫出更穩健的程式碼。實務上,「多加括號、少耍聰明」始終是最安全的原則。