PHP 完全指南 / 第 5 章 — 运算符
第 5 章 — 运算符:算术、比较、逻辑与太空船运算符
5.1 算术运算符
<?php
$a = 10;
$b = 3;
echo $a + $b; // 13 加法
echo $a - $b; // 7 减法
echo $a * $b; // 30 乘法
echo $a / $b; // 3.333... 除法
echo $a % $b; // 1 取模(余数)
echo $a ** $b; // 1000 幂运算(PHP 5.6+)
整除运算符(PHP 7.0+)
<?php
echo intdiv(10, 3); // 3
echo intdiv(-10, 3); // -3
echo intdiv(10, 0); // DivisionByZeroError
组合赋值运算符
<?php
$x = 10;
$x += 5; // $x = $x + 5 → 15
$x -= 3; // $x = $x - 3 → 12
$x *= 2; // $x = $x * 2 → 24
$x /= 4; // $x = $x / 4 → 6
$x %= 4; // $x = $x % 4 → 2
$x **= 3; // $x = $x ** 3 → 8
$x .= "px"; // 字符串拼接 → "8px"
5.2 比较运算符
松散比较 vs 严格比较
<?php
// 松散比较(==)— 会进行类型转换
var_dump(0 == "foo"); // true ⚠️
var_dump("" == null); // true
var_dump(0 == null); // true
var_dump("" == false); // true
var_dump("1" == true); // true
// 严格比较(===)— 类型和值都必须相同(推荐)
var_dump(0 === "foo"); // false ✓
var_dump("" === null); // false ✓
var_dump(1 === true); // false ✓
var_dump("1" === 1); // false ✓
比较运算符汇总
| 运算符 | 松散 | 严格 | 说明 |
|---|---|---|---|
== | ✅ | — | 等于 |
=== | — | ✅ | 全等 |
!= | ✅ | — | 不等 |
!== | — | ✅ | 不全等 |
< | ✅ | — | 小于 |
> | ✅ | — | 大于 |
<= | ✅ | — | 小于等于 |
>= | ✅ | — | 大于等于 |
太空船运算符(<=>)— PHP 7.0+
<?php
// 返回 -1、0 或 1
echo 1 <=> 2; // -1(左 < 右)
echo 1 <=> 1; // 0(相等)
echo 2 <=> 1; // 1(左 > 右)
// 排序示例
$users = [
['name' => 'Charlie', 'age' => 25],
['name' => 'Alice', 'age' => 30],
['name' => 'Bob', 'age' => 28],
];
usort($users, fn($a, $b) => $a['age'] <=> $b['age']);
// 结果: Alice(30), Bob(28), Charlie(25) → 排序后按年龄升序
5.3 逻辑运算符
<?php
$a = true;
$b = false;
var_dump($a && $b); // false AND
var_dump($a || $b); // true OR
var_dump(!$a); // false NOT
var_dump($a xor $b); // true XOR(只有一个为 true)
// 注意优先级差异
// && 优先级高于 ||
// and 优先级低于 =
// or 优先级低于 =
$x = false || true; // $x = (false || true) → true
$y = false or true; // $y = false(因为 or 优先级低于 =)
5.4 字符串运算符
<?php
$greeting = "Hello";
$greeting .= ", World!"; // 拼接
echo $greeting; // Hello, World!
// 字符串自增(PHP 独特行为)
$a = "a";
$a++; // "b"
$z = "z";
$z++; // "aa"(进位)
$num = "9";
$num++; // 10(转为整数)
5.5 位运算符
<?php
$a = 0b1010; // 10
$b = 0b1100; // 12
echo decbin($a & $b); // 1000 AND
echo decbin($a | $b); // 1110 OR
echo decbin($a ^ $b); // 110 XOR
echo decbin(~$a); // ...11110101 NOT
echo decbin($a << 2); // 101000 左移
echo decbin($a >> 1); // 101 右移
// 常见用法:权限管理
define('PERM_READ', 1 << 0); // 001 = 1
define('PERM_WRITE', 1 << 1); // 010 = 2
define('PERM_EXECUTE', 1 << 2); // 100 = 4
$userPerm = PERM_READ | PERM_WRITE; // 011 = 3
var_dump((bool)($userPerm & PERM_READ)); // true
var_dump((bool)($userPerm & PERM_EXECUTE)); // false
5.6 PHP 8.0+ 新运算符
5.6.1 null 合并运算符(??)
<?php
// 如果左边不为 null,返回左边;否则返回右边
$username = $_GET['user'] ?? 'guest';
$deep = $a['b']['c'] ?? $fallback ?? 'default';
// 链式使用
$config = $localConfig ?? $globalConfig ?? $defaultConfig;
5.6.2 null 合并赋值运算符(??=)— PHP 7.4+
<?php
// 仅当变量为 null 时赋值
$options['timeout'] ??= 30;
// 等价于: $options['timeout'] = $options['timeout'] ?? 30;
// 实际应用
$cache[$key] ??= computeExpensiveValue($key);
5.6.3 null 安全运算符(?->)— PHP 8.0+
<?php
class Address {
public ?string $country = null;
}
class User {
public ?Address $address = null;
}
$user = new User();
// 传统写法
$country = $user->address !== null
? ($user->address->country ?? 'Unknown')
: 'Unknown';
// null 安全运算符
$country = $user?->address?->country ?? 'Unknown';
5.6.4 展开运算符(…)
<?php
// 数组展开(PHP 7.4+)
$a = [1, 2, 3];
$b = [...$a, 4, 5]; // [1, 2, 3, 4, 5]
// 合并数组
$defaults = ['color' => 'blue', 'size' => 'medium'];
$options = [...$defaults, 'color' => 'red'];
// ['color' => 'red', 'size' => 'medium']
// 函数参数展开
function sum(int ...$numbers): int {
return array_sum($numbers);
}
$nums = [1, 2, 3, 4, 5];
echo sum(...$nums); // 15
// 命名参数展开(PHP 8.1+)
$config = ['host' => 'localhost', 'port' => 3306];
connect(...$config);
5.7 运算符优先级(常用)
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 最高 | () | 括号 |
** | 幂 | |
++ -- ~ (int) (float) | 一元 | |
* / % | 乘除模 | |
+ - . | 加减拼接 | |
<< >> | 位移 | |
< <= > >= <=> | 比较 | |
== != === !== | 等于 | |
& | 按位 AND | |
^ | 按位 XOR | |
| | 按位 OR | |
&& | 逻辑 AND | |
|| | 逻辑 OR | |
?? | null 合并 | |
? : | 三元 | |
= += -= 等 | 赋值 | |
| 最低 | and xor or | 逻辑(低优先级) |
最佳实践:不确定优先级时,使用括号
()明确表达意图。
5.8 三元运算符与 match
<?php
// 基础三元
$greeting = $hour < 12 ? '早上好' : '下午好';
// 嵌套三元(不推荐,可读性差)
$level = $score > 90 ? 'A'
: ($score > 80 ? 'B'
: ($score > 70 ? 'C' : 'D'));
// PHP 8.0 match 表达式(推荐替代复杂三元/switch)
$level = match (true) {
$score > 90 => 'A',
$score > 80 => 'B',
$score > 70 => 'C',
default => 'D',
};
// match 严格比较
$status = match ($input) {
'active' => 1,
'inactive' => 0,
'deleted' => -1,
default => throw new InvalidArgumentException("Invalid: $input"),
};
5.9 业务场景:电商平台价格计算
<?php
declare(strict_types=1);
class PriceCalculator
{
public function __construct(
private readonly float $price,
private readonly int $quantity,
) {}
public function calculate(
?float $discountPercent = null,
?string $couponCode = null,
float $taxRate = 0.13,
): array {
$subtotal = $this->price * $this->quantity;
// 折扣
$discount = $discountPercent
? $subtotal * ($discountPercent / 100)
: 0.0;
// 优惠券
$couponDiscount = match ($couponCode ?? '') {
'SAVE10' => min($subtotal * 0.1, 50.0), // 最多减 50
'SAVE20' => min($subtotal * 0.2, 100.0),
'' => 0.0,
default => throw new InvalidArgumentException("无效优惠码"),
};
$totalDiscount = $discount + $couponDiscount;
$afterDiscount = max($subtotal - $totalDiscount, 0.0);
$tax = $afterDiscount * $taxRate;
$total = $afterDiscount + $tax;
return [
'subtotal' => round($subtotal, 2),
'discount' => round($totalDiscount, 2),
'tax' => round($tax, 2),
'total' => round($total, 2),
];
}
}
// 使用示例
$calc = new PriceCalculator(99.99, 3);
$result = $calc->calculate(
discountPercent: 10,
couponCode: 'SAVE10',
);
print_r($result);
// Array (
// [subtotal] => 299.97
// [discount] => 79.99
// [tax] => 28.60
// [total] => 248.58
// )
5.10 扩展阅读
上一章:第 4 章 — 变量与类型 下一章:第 6 章 — 控制流