赋值运算符
概述
赋值运算符是 PHP 中最基本的运算符之一,用于将值赋给变量。除了基础的赋值运算符 = 外,PHP 还提供了一系列复合赋值运算符,可以将算术、位运算和字符串操作与赋值合并为一步执行,使代码更加简洁。
核心要点
赋值运算符是右结合的,这意味着 $a = $b = $c 等价于 $a = ($b = $c)。赋值操作本身会返回被赋的值,这使得链式赋值成为可能。
基础概念
运算符一览
| 运算符 | 等价写法 | 说明 |
|---|---|---|
$a = $b | $a = $b | 基础赋值 |
$a += $b | $a = $a + $b | 加法赋值 |
$a -= $b | $a = $a - $b | 减法赋值 |
$a *= $b | $a = $a * $b | 乘法赋值 |
$a /= $b | $a = $a / $b | 除法赋值 |
$a **= $b | $a = $a ** $b | 幂赋值(PHP 5.6+) |
$a %= $b | $a = $a % $b | 取模赋值 |
$a .= $b | $a = $a . $b | 字符串拼接赋值 |
$a &= $b | $a = $a & $b | 按位与赋值 |
$a |= $b | $a = $a | $b | 按位或赋值 |
$a ^= $b | $a = $a ^ $b | 按位异或赋值 |
$a <<= $b | $a = $a << $b | 左移赋值 |
$a >>= $b | $a = $a >> $b | 右移赋值 |
$a ??= $b | $a = $a ?? $b | Null 合并赋值(PHP 7.4+) |
语法与代码示例
基础赋值
php
<?php
declare(strict_types=1);
// 基础赋值
$name = "Alice";
$age = 30;
$isActive = true;
// 赋值表达式返回被赋的值
$a = 5;
$b = ($a = 10); // $b = 10,$a = 10
var_dump($a, $b); // int(10), int(10)
// 链式赋值(右结合)
$x = $y = $z = 0;
var_dump($x, $y, $z); // int(0), int(0), int(0)
// 赋值运算符优先级很低,仅高于 yield/print/and/xor/or
$bool = true && false;
var_dump($bool); // bool(false) —— 先计算 && 再赋值复合算术赋值
php
<?php
declare(strict_types=1);
$counter = 10;
// 加法赋值
$counter += 5; // $counter = $counter + 5 = 15
var_dump($counter); // int(15)
// 减法赋值
$counter -= 3; // $counter = $counter - 3 = 12
var_dump($counter); // int(12)
// 乘法赋值
$counter *= 2; // $counter = $counter * 2 = 24
var_dump($counter); // int(24)
// 除法赋值
$counter /= 4; // $counter = $counter / 4 = 6.0
var_dump($counter); // float(6.0)
// 幂赋值
$value = 2;
$value **= 10; // $value = $value ** 10 = 1024
var_dump($value); // int(1024)
// 取模赋值
$value = 17;
$value %= 5; // $value = $value % 5 = 2
var_dump($value); // int(2)字符串拼接赋值
php
<?php
declare(strict_types=1);
// .= 用于字符串拼接
$html = '<div class="container">';
$html .= '<h1>Hello</h1>';
$html .= '<p>World</p>';
$html .= '</div>';
echo $html . "\n";
// 构建 SQL 查询
$sql = "SELECT * FROM users WHERE 1=1";
$conditions = [];
if (!empty($conditions)) {
$sql .= " AND status = 'active'";
}
$sql .= " ORDER BY created_at DESC LIMIT 10";
echo $sql . "\n";
// 另一种写法:使用数组收集再 implode
$parts = ['SELECT * FROM users', 'WHERE status = ?', 'ORDER BY id ASC'];
$query = implode(' ', $parts);
echo $query . "\n";位运算复合赋值
php
<?php
declare(strict_types=1);
// 权限管理中使用位运算赋值
$readPermission = 1 << 0; // 1
$writePermission = 1 << 1; // 2
$executePermission = 1 << 2; // 4
$permissions = 0;
// 添加权限
$permissions |= $readPermission; // 添加读权限
$permissions |= $writePermission; // 添加写权限
var_dump($permissions); // int(3)
// 移除权限
$permissions &= ~$writePermission; // 移除写权限
var_dump($permissions); // int(1)
// 切换权限(异或)
$permissions ^= $writePermission; // 切换写权限
var_dump($permissions); // int(3)引用赋值
php
<?php
declare(strict_types=1);
// 基础赋值:值拷贝
$a = 10;
$b = $a; // $b 是 $a 的副本
$b = 20;
var_dump($a); // int(10) —— $a 不受影响
// 引用赋值:两个变量指向同一内存
$x = 10;
$y = &$x; // $y 是 $x 的引用
$y = 20;
var_dump($x); // int(20) —— $x 随 $y 改变
// 引用在循环中的使用
$items = ['a', 'b', 'c'];
foreach ($items as &$item) {
$item = strtoupper($item);
}
unset($item); // 建议手动解除引用
print_r($items); // ['A', 'B', 'C']引用赋值的注意事项
- 引用赋值后,修改任一变量都会影响另一个
- 使用
foreach遍历引用后,务必unset引用变量,避免后续代码中的意外修改 - 引用不能重新定义为引用常量(如函数参数的只读引用)
Null 合并赋值 ??=(PHP 7.4+)
php
<?php
declare(strict_types=1);
// ??= 仅在左侧为 null 或未定义时赋值
$config = ['host' => 'localhost'];
// host 已设置,不赋值
$config['host'] ??= '127.0.0.1';
var_dump($config['host']); // string(9) "localhost"
// port 未设置,执行赋值
$config['port'] ??= 3306;
var_dump($config['port']); // int(3306)
// 等价写法对比
$username = null;
$username = $username ?? 'guest'; // 完整写法
$username ??= 'guest'; // 简写(PHP 7.4+)
// 注意:??= 不会处理 $a 为 0、''、false 的情况
$score = 0;
$score ??= 100; // score 仍然是 0,因为 0 不是 null
var_dump($score); // int(0)详细说明
链式赋值的原理
php
<?php
declare(strict_types=1);
// 链式赋值是右结合的
$a = $b = $c = 100;
// 实际解析为:
// $a = ($b = ($c = 100))
// 1. $c = 100,返回 100
// 2. $b = 100,返回 100
// 3. $a = 100
// 链式赋值与复合赋值混用
$x = 10;
$y = 20;
$a = $b = $x + $y; // $a = $b = 30
var_dump($a, $b); // int(30), int(30)赋值与类型系统
php
<?php
declare(strict_types=1);
// 赋值不会改变变量类型(除非值本身是不同类型)
$num = 42; // int
$num = 3.14; // 变为 float
// 赋值为不同类型是完全合法的(PHP 是动态类型语言)
$var = "hello"; // string
$var = [1, 2]; // array
$var = true; // bool
// 解构赋值(PHP 7.1+)
$coordinates = [10, 20, 30];
[$x, $y, $z] = $coordinates;
var_dump($x, $y, $z); // int(10), int(20), int(30)
// 带键名的解构赋值
$user = ['name' => 'Alice', 'age' => 30];
['name' => $name, 'age' => $age] = $user;
var_dump($name, $age); // string(5) "Alice", int(30)
// 交换变量(PHP 7.1+ 解构)
$a = 1;
$b = 2;
[$a, $b] = [$b, $a];
var_dump($a, $b); // int(2), int(1)实战示例
配置初始化
php
<?php
declare(strict_types=1);
class AppConfig
{
private array $config;
public function __construct(array $defaults = [])
{
$this->config = $defaults;
}
public function set(string $key, mixed $value): void
{
$this->config[$key] = $value;
}
public function get(string $key, mixed $default = null): mixed
{
return $this->config[$key] ?? $default;
}
}
// 使用 ??= 初始化默认配置
$config = new AppConfig();
$config->set('debug', true);
$config->set('timeout', 30);
// 动态设置默认值
$settings = [
'host' => 'localhost',
'port' => 3306,
];
$settings['charset'] ??= 'utf8mb4';
$settings['collation'] ??= 'utf8mb4_unicode_ci';
print_r($settings);累加器模式
php
<?php
declare(strict_types=1);
function calculateStats(array $numbers): array
{
$sum = 0;
$count = 0;
$max = PHP_INT_MIN;
$min = PHP_INT_MAX;
foreach ($numbers as $num) {
$sum += $num;
$count += 1;
$max = max($max, $num);
$min = min($min, $num);
}
return [
'sum' => $sum,
'count' => $count,
'average' => $count > 0 ? $sum / $count : 0,
'max' => $max,
'min' => $min,
];
}
$stats = calculateStats([15, 23, 8, 42, 16]);
print_r($stats);
// sum: 104, count: 5, average: 20.8注意事项
??=不等同于=:$a ??= $b仅在$a为null时赋值,$a = $b总是赋值- 引用赋值影响原变量:
$b = &$a后修改$b会改变$a foreach引用遍历后要unset:避免循环变量污染后续代码- 复合赋值有类型转换:
$str .= 0会将整数隐式转换为字符串 - 赋值是表达式不是语句:
$a = 5的值是5,可以在if等语句中使用
最佳实践
- 使用复合赋值简化代码:
$counter += 1优于$counter = $counter + 1 - 使用
??=设置默认值:比if (!isset($a)) $a = $b;更简洁 - 引用赋值谨慎使用:仅在明确需要共享状态时使用(如大数组避免拷贝开销)
- 链式赋值保持简洁:仅在初始化多个变量为同一值时使用
- 字符串拼接考虑
implode:多次拼接时先收集到数组再implode,性能更好
进阶用法
调试与测试技巧
php
<?php
declare(strict_types=1);
// 单元测试辅助函数
function createTestResource(): mixed
{
return match (true) {
default => new stdClass(),
};
}
// 调试输出函数
function debugOutput(mixed , string = ''): void
{
= ? ": " : '';
.= print_r(, true);
fwrite(STDERR, . "\n");
}
// 性能基准测试
function benchmark(callable , int = 1000): float
{
= hrtime(true);
for ($i = 0; $i < $iterations; $i++) {
$fn();
}
return (hrtime(true) - $start) / 1e9;
}日志记录实践
php
<?php
declare(strict_types=1);
/**
* 简易日志记录器
*/
class SimpleLogger
{
private string $logFile;
private string $level = 'INFO';
public function __construct(string $logFile)
{
$this->logFile = $logFile;
}
public function info(string $message, array $context = []): void
{
$this->log('INFO', $message, $context);
}
public function warning(string $message, array $context = []): void
{
$this->log('WARNING', $message, $context);
}
public function error(string $message, array $context = []): void
{
$this->log('ERROR', $message, $context);
}
private function log(string $level, string $message, array $context): void
{
$timestamp = date('Y-m-d H:i:s');
$contextStr = $context ? ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
$line = "[{$timestamp}] [{$level}] {$message}{$contextStr}\n";
file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
}配置与环境检测
php
<?php
declare(strict_types=1);
// 环境检测工具
class EnvironmentChecker
{
public static function checkRequirements(array $requirements): array
{
$results = [];
foreach ($requirements as $name => $check) {
$results[$name] = is_callable($check) ? $check() : false;
}
return $results;
}
public static function getSystemInfo(): array
{
return [
'php_version' => PHP_VERSION,
'os' => PHP_OS,
'sapi' => PHP_SAPI,
'memory_limit' => ini_get('memory_limit'),
'max_execution_time' => ini_get('max_execution_time'),
'loaded_extensions' => get_loaded_extensions(),
];
}
}常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 网络问题/配置错误 | 检查配置,增加超时时间 |
| 权限不足 | 文件/目录权限 | 使用 chmod/chown 修正 |
| 性能下降 | 索引缺失/数据量大 | 添加索引,优化查询 |
| 数据不一致 | 并发冲突/事务残留 | 使用锁机制和事务 |
| 内存溢出 | 大数据集/未释放资源 | 增大内存限制,分批处理 |
故障排除步骤
- 检查错误日志和异常信息
- 确认配置和环境是否正确
- 使用调试工具逐步排查
- 参考官方文档查找已知问题
版本兼容性说明
| 功能 | 最低版本 | 说明 |
|---|---|---|
| 基础功能 | PHP 8.1 | 本文档基准版本 |
| 只读属性 | PHP 8.1 | public readonly 修饰符 |
| 枚举类型 | PHP 8.1 | enum 类型和 match 表达式 |
| Fiber | PHP 8.1 | 协程/轻量级并发 |
| 命名参数 | PHP 8.0 | foo(arg_name: value) |
| 联合类型 | PHP 8.0 | `int |
| Null 安全运算符 | PHP 8.0 | $obj?->method() |
| 析构器 promotion | PHP 8.0 | __construct(public $x) |
php
<?php
declare(strict_types=1);
// 版本兼容性检测
function ensureVersion(string $minVersion): void
{
if (version_compare(PHP_VERSION, $minVersion, '<')) {
throw new RuntimeException(
sprintf('需要 PHP %s+, 当前版本: %s', $minVersion, PHP_VERSION)
);
}
}
ensureVersion('8.1.0');