强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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 章 — 控制流