许多 PHP 文件(特别是类文件、配置文件、库文件)末尾没有 ?> 闭合标签。这不是疏忽,而是刻意的最佳实践。
PHP 解析器将 ?> 之后的所有内容(包括换行、空格、BOM、不可见字符)作为直接输出发送给浏览器。这会导致:
header()、setcookie()、session_start()。ob_start() 无法捕获闭合标签后的输出。<?php
// config.php
define('DB_HOST', 'localhost');
?> <-- 这里有一个不可见的空格和换行
<?php
// index.php
require 'config.php';
header('Content-Type: application/json'); // 警告:Headers already sent!
echo json_encode(['status' => 'ok']);
PHP 官方编码规范(PSR-12 / Zend / Symfony 等)均规定:纯 PHP 文件必须省略闭合标签。
| 文件类型 | 是否需要 ?> | 说明 |
|---|---|---|
| 纯 PHP 类/函数/配置/引导文件 | 否(禁止) | 防止尾部空白输出 |
| 模板文件(.phtml, .php 作为视图) | 是 | 需输出 HTML,闭合标签后可直接写 HTML |
| 包含 HTML 片段的 PHP 文件 | 视情况 | 若文件以 HTML 结尾,保留 ?>;若以 PHP 代码结尾,省略 |
phpcs (PHP_CodeSniffer) 规则 PSR12.Files.ClosingTag 会强制报错。/\?\>\s*$/ 模式。纯 PHP 文件末尾省略 ?> 是零成本、高收益的防御性编程习惯。它消除了一整类「莫名其妙的 Headers already sent / JSON 解析失败」Bug,且被主流框架(Laravel, Symfony, ThinkPHP)及规范(PSR-12)强制要求。养成这个习惯,让代码更干净、部署更安心。