介紹 PHP 中運算子的用法,包含種類、優先順序、算術運算子 (Arithmetic Operator)、指派運算子 (Assignment Operator)、位元運算子 (Bitwise Operator)、比較運算子 (Comparison Operator)、三元運算子 (Ternary Operator)和錯誤控制運算子 (Error Control Operator)。

簡介

種類

透過提供一些數值給運算子 (Operator,或運算符) 進行運算,進而得到一個運算結果,可以想成類似函式的回傳,另外被運算的數值稱為運算元 (Operand)。

依據運算元的個數,運算子可以分為三種:

  • 一元運算子,只有一個運算元,例如:!, ++ 等。
  • 二元運算子,包含兩個運算元,大部分都屬於這類。
  • 三元運算子,包含三個運算元,只有 ? : 運算子屬於此類。

而依據性質,可以分為:

  • 算術運算子 (Arithmetic Operator)
  • 指派運算子 (Assignment Operator)
  • 位元運算子 (Bitwise Operator)
  • 比較運算子 (Comparison Operator)
  • 三元運算子 (Ternary Operator)
  • 錯誤控制運算子 (Error Control Operator)
  • 執行運算子 (Execution Operator)
  • 增值/減值運算子 (Incrementing/Decrementing Operator)
  • 邏輯運算子 (Logical Operator)
  • 字串運算子 (String Operator)
  • 陣列運算子 (Array Operator)
  • 型別運算子 (Type Operator)

運算子優先順序

不同的運算子有不同的優先順序 (Precedence),例如:1 + 2 * 3 是 7 而不是 9,乘號 (*) 的優先順序大於加號 (+) 而先做。可以利用括號來增加優先順序,例如:(1 + 2) * 3 為 9。如果優先順序相同則依據運算子的結合律 (Associativity) 決定先做左或右邊。以下為運算子由高至低的順序表:

結合律運算子
clone new
[
++ – ~ - (int) (float) (string) (array) (object) (bool) @
instanceof
!
* / %
+ - .
<< >>
< <= > >= <>
== != === !==
&
^
|
&&
||
? :
= += -= *= /= .= %= &=
and
xor
or
,

結合律左右的解釋範例如下:

1
2
3
4
5
6
7
8
// 結合律: 左
var_dump(7 * 3 / 3); // int(7), => 21 / 3
var_dump(7 / 3 * 3); // float(7), => 2.3333.. * 3 先轉為 float

// 結合律: 右
$a = 1;
$b = 2;
$a = $b += 3; // $b = 5, $a = 5

但有時候指派 (=) 雖然順序較後,但仍然會先進行運算:

1
2
3
$a = false;
$b = true;
var_dump(!$a = $b); // bool(false)

算術運算子

算術運算子 (Arithmetic Operator) 就如同數學的四則運算一般,包含以下運算子:

範例名稱說明
-$a負號將 $a 正負變號
$a + $b加法$a 和 $b 的總和
$a - $b減法$a 減去 $b
$a * $b乘法$a 乘上 $b
$a / $b除法$a 除以 $b
$a % $b取餘數$a 除以 $b 的餘數 (餘數的正負號與 $a 相同)

整數除不盡時會轉為浮點數,以及大整數取餘數時可能會有問題,可以參考 PHP 教學 - 資料型態 (Data Type) - 上

指派運算子

基本的指派運算子 (Assignment Operator) 符號是 (=),你可能會把它想成數學的等於,但實際上不能這樣想,正確的意思是:將右邊的結果放入左邊。

陣列的宣告時使用 (=>) 的符號來指派陣列元素的內容。除此之外,指派運算子可以和二元運算子結合使用,用法如下:

$a X= $b 相當於 $a = $a X $b,X 代換為任意二元運算子,例如:$a += $b 相當於 $a = $a + $b。

1
2
3
4
5
6
$num = 3;
$num *= 5; // $num: 15

$teletubbies = array('dindin' => '紫色', 'lala' => '黃色');
$fool = "Lala是";
$fool .= $teletubbies['lala']; // $fool: Lala 是黃色

位元運算子

位元運算子 (Bitwise Operator) 能夠對整數的位元進行運算,包含以下運算子:

範例名稱說明
$a & $b交集 (And)$a 和 $b 的位元皆為 1 的部份為 1
$a | $b聯集 (Or)$a 或 $b 的位元其中一方為 1 的部份為 1
$a ^ $b互斥 (Xor)$a 和 $b 的位元只有其中一方為 1 的部份為 1
~ $a補數 (Not)$a 為 1 的部份為 0,為 0 的部份為 1
$a << $b左移$a 往左移動 $b 個位元 (意同 $a 乘以 2 的 $b 次方)
$a >> $b右移$a 往右移動 $b 個位元 (意同 $a 除以 2 的 $b 次方之整數)

向左位移時,正負號不會保留;而向右位移時,正負號會保留。進行位元運算時,如果不是整數型別會先轉成整數型別處理,但當兩邊都是字串型別時,會以字元的 ASCII 碼來進行處理 (位移運算除外)。

位移運算的位移量會取平台位元數的餘數進行運算,例如在 32 位元平台的 $a << 33 會轉為 $a << (33 % 32) 相當於 $a << 1,一些範例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 只顯示最右邊8個bit
function toBits ($num, $bits = 8) {
return substr(sprintf("%0{$bits}b", $num), -$bits);
}

$a = 55;
$b = 66;
echo toBits($a) . "\n"; // 00110111
echo toBits($b) . "\n"; // & 01000010
//-----------
echo toBits($a & $b) . "\n"; // 00000010 : 2

// 00110111
// | 01000010
//-----------
echo toBits($a | $b) . "\n"; // 01110111 : 119

// 00110111
// ^ 01000010
//-----------
echo toBits($a ^ $b) . "\n"; // 01110101 : 117

// ~ 00110111
//------------
echo toBits(~$a) . "\n"; // 11001000 : -56

// 00110111 << 2
//------------
echo toBits($a << 2) . "\n"; // 11011100 : 220

// 00110111 >> 33
//------------
echo toBits($a >> 33) . "\n"; // 00011011 : 27

比較運算子

比較運算子 (Comparison Operator) 可以比較兩個值,並將結果以布林回傳,包含以下運算子:

範例名稱說明
$a == $b相等如果 $a 和 $b 的值相等則為 TRUE
$a === $b完全相等如果 $a 和 $b 的值與型別都相等則為 TRUE
$a != $b不相等如果 $a 和 $b 的值不相等則為 TRUE
$a <> $b不相等如果 $a 和 $b 的值不相等則為 TRUE
$a !== $b不完全相等如果 $a 和 $b 的值或型別不相等則為 TRUE
$a < $b小於如果 $a 小於 $b 則為 TRUE
$a > $b大於如果 $a 大於 $b 則為 TRUE
$a <= $b小於等於如果 $a 小於等於 $b 則為 TRUE
$a >= $b大於等於如果 $a 大於等於 $b 則為 TRUE

如果字串和數字比較或兩個字串皆為數字的形式比較時,字串會先轉為數字後比較,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var_dump(0 == "a");       // bool(true), 轉為數字當作 0 和 0
var_dump(0 === "a"); // bool(false) 型別不同
var_dump("1" != "01"); // bool(false), 轉為數字當作 1 和 1
var_dump("10" <> "1e1"); // bool(false), 轉為數字當作 10 和 10
var_dump(100 != "1e2"); // bool(false), 轉為數字當作 100 和 100
var_dump(100 !== "1e2"); // bool(true), 型別不同

switch ("a") {
case 0:
echo "會進來"; // 轉為數字 0
break;
case "a":
echo "不會進來"; // 已經進入 case 0, 永遠不會進入此處
break;
}

各種型別進行比較時,會根據以下的規則來做處理,情況重疊時以較上方的規則為準:

型別1型別2結果
數字形式字串數字形式字串轉為數字進行比較 。
字串字串以字串內容進行比較 。
字串NULLNULL 轉為空字串 "" 進行比較 。
布林任何型別轉為布林進行比較,且 FALSE < TRUE。
物件物件不同類別無法比較,相同類別在 PHP 4 比較方式和陣列一樣,在 PHP 5 中更為複雜,在之後的章節再做討論。
實作 toString物件任何型別toString() 結果字串進行比較,與字串比較規則相同。
物件字串物件永遠比較大。
陣列陣列陣列必須有相同 Key 的元素才能比較,會逐值比較。
陣列任何型別陣列永遠比較大。
數字任何型別轉為數字進行比較。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var_dump("10" == "1e1");  // bool(true), 轉為數字當作 10 和 10
var_dump("b" > "a"); // bool(true)
var_dump("" == NULL); // bool(true)
var_dump(FALSE == NULL); // bool(true)
var_dump(2 > TRUE); // bool(false), 轉為布林 TRUE > TRUE

class A {
function __toString() {
return "A";
}
}
$a = new A;
$s = new stdClass;
// $a 和 $s 無法比較
var_dump($a == $s); // bool(false)
var_dump($a > $s); // bool(false)
var_dump($a < $s); // bool(false)
var_dump($a != $s); // bool(true)

var_dump($a == "A"); // bool(true), 轉為字串 "A" == "A"
var_dump($s > "9527"); // bool(true), 物件永遠較大

var_dump(array("fool" => 55) < array("fool" => 66)); // bool(true)
var_dump(array() > 9527); // bool(true), 陣列永遠較大
var_dump(55 < "66"); // bool(true), 轉為數字比較

可參考 PHP 教學 - 資料型態 (Data Type) - 上PHP 教學 - 資料型態 (Data Type) - 下 有關轉型的部份。

三元運算子

三元運算子 (Ternary Operator) 是另一種條件運算子,符號為 (?:),語法如下:

1
(expr1) ? (expr2) : (expr3)

當 expr1 成立時,則回傳 expr2;否則回傳 expr3。

1
2
// 當 $_POST['action'] 沒有值的時候,$action 給預設值 'default';否則為 $_POST['action']
$action = (empty($_POST['action'])) ? 'default' : $_POST['action'];

在 PHP 5.3 之後新增用法,能夠省略 expr2:

1
(expr1) ?: (expr3)

回傳第一個不為 FALSE 的結果,例如:

1
2
3
4
5
6
7
8
9
// 與上面範例的意義相同
$action = $_GET['action'] ?: 'default';

$a = "";
$b = "0";
$d = "first";
$e = "second";
$str = $a ?: $b ?: $c ?: $d ?: $e;
echo $str; // first, 取得第一個轉為布林不為 FALSE 的值

類似 JavaScript 的 || 用法。

錯誤控制運算子

錯誤控制運算子 (Error Control Operator) 使用 (@) 符號,可以用來忽略錯誤訊息,若 php.initrack_errors 設定為 On 時,隱藏的訊息會存在預定義變數 $php_errormsg 中:

1
2
3
4
5
ini_set("error_reporting", E_ALL);
$f = file("nofile"); // Warning: file(nofile): failed to open stream: No such file or directory in K:\mowes\www\learn\php\test.php on line 3
$f = @file("nofile"); // 不會顯示
// php.ini 的 track_errors 有開啟時, 隱藏的訊息會存在 $php_errormsg
echo $php_errormsg; // file(nofile): failed to open stream: No such file or directory

延伸閱讀

上一篇 PHP 教學 - 常數 (Constants)
下一篇 PHP 教學 - 運算子 (Operators) - 下