PHP 8.3 要求所有控制结构(if/else/while/foreach/switch)、函数、方法及构造函数体必须显式使用大括号,右括号后需空格,{独占行,缩进统一为4空格,}对齐缩进,以防止逻辑错误并提升静态分析与IDE支持能力。

if/else 语句中大括号必须显式写出
PHP 8.3 没有改变语法层面的大括号可选性,单语句 if 依然允许省略 {}。但实际项目中,**任何 if、else、elseif、while、foreach 的控制块都应强制使用大括号**——这不是风格偏好,而是防止逻辑漂移的硬性要求。
常见错误现象:在已有单行 if 后追加第二行语句,却忘记补上大括号,导致第二行无条件执行:
if (isset($user))
$user = filter_var($user, FILTER_SANITIZE_STRING);
log_access($user); // 这行永远执行!
正确写法(注意空格与换行):
if (isset($user)) {
$user = filter_var($user, FILTER_SANITIZE_STRING);
log_access($user);
}
- 右括号
)和左大括号{之间必须有一个空格 -
{必须独占一行,不能跟在条件后 - 所有语句体必须缩进一次(推荐 4 空格)
-
}必须单独成行,且与对应{缩进对齐
switch/case 中的花括号位置不可省略
PHP 8.3 明确要求 switch 结构体必须用 {} 包裹整个主体,且 case 分支内即使只有一条语句,也建议统一用大括号包裹(尤其当未来可能扩展时)。
立即学习“PHP免费学习笔记(深入)”;
错误示范(结构体无大括号,违反 PSR-12):
switch ($status) {
case 'active':
echo 'Online';
break;
default:
echo 'Offline';
}
正确写法(switch 主体必须有 {},case 内部保持一致缩进):
switch ($status) {
case 'active': {
echo 'Online';
break;
}
default: {
echo 'Offline';
break;
}
}
-
case后不加冒号直接接{是合法的,且更利于静态分析工具识别作用域边界 - 每个
case块独立包裹,避免break遗漏导致的 fall-through 意外穿透 - PHP 8.3 的类型推导和 IDE 补全在显式块结构下更准确
类方法和函数体内必须用大括号包裹主体
这是 PHP 8.3 兼容现代编码规范(如 PSR-12)的底线要求。哪怕方法体只有一行 return,也禁止省略 {}。
例如,以下写法在 PHP 8.3 中虽能运行,但属于反模式:
public function getName()
return $this->name;
必须写成:
public function getName(): string {
return $this->name;
}
- 缺少大括号会破坏 IDE 的代码折叠、断点设置和类型提示能力
- PHPStan、Psalm 等静态分析工具默认要求完整块结构,否则报错
- 配合
#[Override]使用时,若方法体无{},某些版本解析器会误判签名完整性
只读属性初始化与构造函数中的大括号一致性
PHP 8.3 支持只读属性参数提升(public readonly string $name),但构造函数体仍需显式大括号包裹——哪怕它只是调用 parent::__construct() 或空操作。
错误示例(构造函数体被省略):
class User {
public function __construct(public readonly string $name) {}
}
这在语法上合法,但不符合团队协作规范;更危险的是后续添加逻辑时容易遗漏大括号:
class User {
public function __construct(public readonly string $name)
$this->validateName($name); // ❌ 无大括号,$this->validateName 总是执行
}
推荐写法(显式、可扩展、与 #[Override] 兼容):
class User {
public function __construct(public readonly string $name) {
$this->validateName($name);
}
private function validateName(string $name): void {
if (empty($name)) {
throw new InvalidArgumentException('Name cannot be empty');
}
}
}
- 构造函数体的大括号不是装饰,而是作用域边界,影响
$this绑定和异常捕获范围 - 只读属性的深拷贝(
__clone)也依赖显式块结构来控制赋值时机 - 动态属性弃用警告(
E_DEPRECATED)不会因大括号缺失而绕过,但结构清晰能更快定位问题源头
真正容易被忽略的不是“要不要写大括号”,而是“什么时候开始写”——从第一个 if 就该写,而不是等代码变复杂了再补。一旦形成习惯,{ 和 } 就不再是格式负担,而是逻辑锚点。



















