PHP 编码规范详解
PHP 编码规范 旨在提供一套指导原则和最佳实践,以确保 PHP 代码的一致性、可读性、可维护性和团队协作效率。在 PHP 社区中,PSR (PHP Standards Recommendations) 是最广泛接受和遵循的编码规范。遵循这些规范不仅能让你的代码更容易被其他 PHP 开发者理解,也能提高代码本身的质量和减少潜在错误,同时促进不同框架和库之间的互操作性。
核心思想:一致性至关重要。代码是写给人看的,不是机器。清晰、简洁、可读的代码能够极大地提高开发效率和项目成功率。遵循 PSR 规范,让你的代码更具通用性和专业性。
一、PHP 编码哲学与 PSR
PHP 语言虽然以其灵活性和“快速启动”而闻名,但其社区也逐渐形成了一套成熟的编码约定,以解决早期版本中常见的代码风格混乱问题。PSR (PHP Standards Recommendations) 正是这些约定的核心。
PSR 是什么?
PSR 是由 PHP 框架互操作性组 (PHP Framework Interoperability Group, FIG) 制定和推荐的一系列规范。它并非强制性标准,但被绝大多数现代 PHP 框架、库和开发者广泛接受和遵循。
主要相关的 PSR 规范:
- PSR-1 (Basic Coding Standard):基本编码标准,涵盖了最基础的命名、文件结构等。
- PSR-2 (Coding Style Guide):编码风格指南,扩展了 PSR-1,定义了更详细的格式化规则(如缩进、空格、括号位置等)。
- PSR-12 (Extended Coding Style Guide):扩展编码风格指南,取代了 PSR-2,并与 PHP 7.0+ 的新特性保持一致,提供了更全面的风格规则。
- PSR-4 (Autoloader):自动加载规范,定义了文件路径到类名的映射规则,是现代 PHP 项目类自动加载的基础。
为什么它如此重要?
- 统一性:遵循 PSR 的 PHP 代码在风格上高度一致,降低了阅读和理解他人代码的认知负担。
- 互操作性:PSR-4 等规范使得不同的 PHP 库和框架可以无缝地集成和协作。
- 专业性:遵循社区约定是成为一名合格的 PHP 开发者和构建高质量项目的重要标志。
- 可维护性:一致且清晰的代码更容易维护和调试。
二、自动化工具
在现代 PHP 开发中,自动化工具是强制执行编码规范的得力助手,可以大幅减少手动审查的工作量。
2.1 PHP-CS-Fixer (代码风格修复工具)
- 独断专行 (Opinionated):
PHP-CS-Fixer是一款功能强大的代码风格修复工具,它可以自动检测并修复代码中不符合 PSR 规范(或其他配置的风格)的问题。 - 优点:解决了团队内部关于代码格式的争论,所有代码都将拥有统一的风格。
- 安装:
composer require friendsofphp/php-cs-fixer --dev - 配置 (
.php-cs-fixer.dist.php示例):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$finder = (new PhpCsFixer\Finder())
->in(__DIR__)
->exclude('var')
->exclude('vendor')
;
return (new PhpCsFixer\Config())
->setRules([
'@PSR12' => true, // 遵循 PSR-12 规范
'array_syntax' => ['syntax' => 'short'], // 短数组语法 `[]`
'cast_spaces' => ['space' => 'none'], // 强制类型转换时不加空格 (e.g., (string)$var)
'concat_space' => ['spacing' => 'none'], // 连接符 `.` 两侧不加空格
'declare_strict_types' => true, // 声明 strict_types=1
'global_namespace_import' => ['import_classes' => true, 'import_constants' => true, 'import_functions' => true],
'ordered_imports' => ['sort_algorithm' => 'alpha'], // 导入语句按字母排序
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false], // 补充缺少的 @param
'phpdoc_order' => true, // PHP Doc Tags 顺序
'phpdoc_to_comment' => false, // 不将 PHP Doc 转换为单行注释
'single_line_comment_style' => ['comment_types' => ['hash']], // 单行注释用 `//`
'trailing_comma_in_multiline' => ['elements' => ['arrays', 'parameters', 'arguments']], // 多行数组、参数、调用添加尾部逗号
'semicolon_after_instruction' => true, // 语句后必须有分号
'no_unused_imports' => true, // 移除未使用的导入
])
->setFinder($finder)
; - 使用:
1
2vendor/bin/php-cs-fixer fix # 修复所有文件
vendor/bin/php-cs-fixer fix src/Controller/MyController.php # 修复单个文件
2.2 PHP_CodeSniffer (代码风格检查工具)
- 静态分析:
PHP_CodeSniffer(包括phpcs和phpcbf) 是一个用于检查 PHP 代码是否符合预设编码标准(如 PSR-12)以及发现常见编程错误的工具。 - 优点:在代码提交前发现风格和潜在的运行时问题。
phpcbf可以自动修复一些问题。 - 安装:
composer require squizlabs/php_codesniffer --dev - 配置 (
phpcs.xml示例):1
2
3
4
5
6
7
8
9
<ruleset name="MyProject">
<description>My custom coding standard based on PSR12.</description>
<rule ref="PSR12"/> <!-- 遵循 PSR-12 规范 -->
<!-- 可以添加或排除特定的规则 -->
<exclude name="PSR1.Classes.ClassDeclaration.MultipleClasses"/>
<file>src</file>
<file>tests</file>
</ruleset> - 使用:
1
2
3vendor/bin/phpcs # 检查所有文件
vendor/bin/phpcs src/Controller/MyController.php # 检查单个文件
vendor/bin/phpcbf # 自动修复部分问题
三、基本编码标准 (PSR-1, PSR-12 Essentials)
这些是 PHP 代码最基础且最常自动化的格式和结构规则。
3.1 PHP 标签
<?php和<?=:永远使用标准的<?php和<?=(用于echo)标签。避免短标签:禁止使用短开标签
<?。1
2
3
4
5
6// Good
echo 'Hello';
'World'; // Good
// <? echo 'Bad'; // Bad
3.2 文件编码
- UTF-8 (无 BOM):所有 PHP 文件都必须使用 UTF-8 编码,并且不带字节顺序标记 (BOM)。
3.3 文件结尾和类文件
?>标签:仅包含 PHP 代码的文件,文件末尾的?>关闭标签可以省略。强烈建议省略,以防止意外输出空白字符导致 HTTP 头发送问题。每文件一类:每个文件应该只包含一个类、接口、trait 或枚举。
1
2
3
4
5
6
7
8// Good - 没有关闭标签
namespace App\Entity;
class User
{
// ...
}
四、格式化 (PSR-12 Essentials)
这些规则通常由 PHP-CS-Fixer 或 PHP_CodeSniffer 自动处理。
4.1 缩进 (Indentation)
- 4 个空格:每个缩进级别使用 4 个空格。绝不允许使用 Tab 字符。
4.2 行长度 (Line Length)
- 软限制 120 字符:虽然没有硬性限制,但建议每行不超过 120 个字符。超过 120 字符的行应拆分。
- 硬限制 80 字符 (推荐):强烈建议将行长度限制在 80 个字符以内,这在代码审查和分屏显示时效果最佳。
4.3 空行 (Blank Lines)
函数/方法之间:类中的方法定义之间用一个空行分隔。
逻辑块之间:在函数或方法内部,可以使用空行来分隔逻辑相关的代码块,提高可读性。
文件末尾:文件必须以单个非空白行结束。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace App\Service;
class UserService
{
public function getUser(int $id): ?User
{
// Some logic here
$user = $this->repository->find($id);
// More logic or validation
return $user;
}
public function createUser(array $data): User
{
// ...
}
}
4.4 声明块 (use, const, property)
use声明:use声明必须在命名空间声明之后,类、接口、trait 声明之前。- 每条
use声明语句必须独立成行。 use块必须在内部保持一行空白。- 推荐按字母顺序排序。
1
2
3
4
5
6
7
8
9
10
11
12
13
namespace App\Controller;
use App\Entity\User;
use App\Service\UserService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class UserController extends AbstractController
{
// ...
}属性声明:
- 每个类属性必须单独声明。
- 属性的类型声明和默认值必须与属性名在同一行。
- 属性的可见性(
public,protected,private)必须在var关键字(如果使用)或类型声明之前。
1
2
3
4
5
6
7
8
class Product
{
public int $id;
protected string $name = '';
private float $price = 0.0;
}
4.5 结构体 (Control Structures)
if,elseif,else:- 关键字后跟一个空格。
- 左括号
(和右括号)之间没有空格。 - 代码块的左花括号
{必须在条件语句的同一行,并与if关键字用一个空格分隔。 - 右花括号
}必须在新行。 else和elseif必须与上一个代码块的右花括号在同一行。
1
2
3
4
5
6
7
8
9
if ($condition) {
// code
} elseif ($otherCondition) {
// code
} else {
// code
}for,foreach,while,do-while:遵循与if结构相同的格式化规则。switch:- 关键字后跟一个空格,左括号
(和右括号)之间没有空格。 - 左花括号
{在同一行,右花括号}在新行。 case和default关键字必须缩进一层。break和continue关键字必须与case内部的代码块在同一缩进级别。case内部的代码块必须缩进一层。
1
2
3
4
5
6
7
8
9
10
11
12
13
switch ($expression) {
case 0:
$message = 'Zero';
break;
case 1:
$message = 'One';
break;
default:
$message = 'Other';
break;
}- 关键字后跟一个空格,左括号
4.6 函数和方法
可见性:必须声明方法的所有可见性(
public,protected,private)。abstract和final必须在可见性之前。static必须在可见性之后。函数声明:
- 函数名与左括号
(之间没有空格。 - 参数列表的左括号
(和右括号)之间没有空格。 - 每个参数前应有类型提示。
- 参数之间用逗号
,分隔,逗号后跟一个空格。 - 参数列表过长时,可以在每个参数后换行,并进行适当缩进。
- 返回类型声明
:<type>必须紧跟右括号),之间没有空格。 - 左花括号
{必须在函数签名的同一行,并用一个空格分隔。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass
{
public static function staticMethod(
string $param1,
?int $param2 = null
): string {
// ...
return 'result';
}
private function calculateValue(int $a, int $b): int
{
return $a + $b;
}
}- 函数名与左括号
五、命名规范 (Naming Conventions)
PSR 规范对命名有严格的规定。
5.1 类、接口、Trait、枚举
PascalCase(大驼峰命名法):每个单词的首字母大写,不使用下划线。1
2
3
4
5
6
7
8
9
10
11
12
13
namespace App\Entity;
class UserProfile
{
// ...
}
interface PaymentGateway
{
// ...
}
5.2 类常量
ALL_CAPS(全大写,下划线分隔):所有字母大写,单词之间用下划线_分隔。1
2
3
4
5
6
7
class Foo
{
public const VERSION = '1.0';
public const STATUS_ACTIVE = 1;
}
5.3 属性 (Properties)
camelCase(小驼峰命名法):第一个单词的首字母小写,后续单词的首字母大写。- 可见性:必须声明属性的可见性(
public,protected,private)。
1
2
3
4
5
6
7
8
class User
{
public int $id;
protected string $firstName;
private string $emailAddress;
}- 可见性:必须声明属性的可见性(
5.4 方法 (Methods)
camelCase(小驼峰命名法):第一个单词的首字母小写,后续单词的首字母大写。- 可见性:必须声明方法的所有可见性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class UserService
{
public function getUserById(int $id): User
{
// ...
}
protected function hashPassword(string $password): string
{
// ...
}
}
5.5 函数 (Functions)
- 全局函数:虽然现代 PHP 开发中应尽量避免全局函数,但如果使用,也应遵循
camelCase。
5.6 局部变量
camelCase(小驼峰命名法):与属性和方法类似。1
2
3
4
5
6
7
8
9
10
11
function calculateTotal(array $items): float
{
$totalAmount = 0.0;
foreach ($items as $itemPrice) {
$totalAmount += $itemPrice;
}
return $totalAmount;
}
六、PHPDoc (文档块)
PHPDoc(PHP 文档块):所有类、方法、函数、属性都应该有 PHPDoc 文档块。它不仅提供文档,还能帮助 IDE 进行代码提示和静态分析。标准:遵循 PSR-5 (PHPDoc Standard) 规范 (尽管它目前仍是 Draft 状态,但被广泛接受)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* Represents a user in the application.
*
* @property int $id The user's unique identifier.
* @property string $name The user's full name.
*/
class User
{
/**
* User ID.
*
* @var int
*/
public int $id;
/**
* Returns the user's full name.
*
* @param string $greeting An optional greeting prefix.
* @return string The full name with greeting.
* @throws \InvalidArgumentException If the greeting is empty.
*/
public function getName(string $greeting = ''): string
{
if (empty($greeting)) {
throw new \InvalidArgumentException('Greeting cannot be empty.');
}
return $greeting . ' ' . $this->name;
}
}常用标签:
@param,@return,@throws,@var,@deprecated,@see,@link等。
七、类型提示 (Type Hints) (PHP 7.0+)
强制使用:尽可能为函数参数、返回值和类属性添加类型提示。这能显著提高代码的清晰度、健壮性和可维护性。
标量类型:
int,float,string,bool,array。复合类型:
object,iterable,callable。特殊类型:
void,null(PHP 7.1+),mixed(PHP 8.0+),static,self,parent。联合类型:
int|string(PHP 8.0+)。属性类型:
public string $name;(PHP 7.4+)。严格类型:在文件顶部声明
declare(strict_types=1);,确保类型提示严格执行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27declare(strict_types=1);
namespace App\Utils;
class Calculator
{
public function add(int $a, int $b): int
{
return $a + $b;
}
public function divide(float $numerator, float $denominator): float|null
{
if ($denominator === 0.0) {
return null;
}
return $numerator / $denominator;
}
private string $status; // PHP 7.4+ 属性类型
public function __construct(string $initialStatus)
{
$this->status = $initialStatus;
}
}
八、总结
PHP 编码规范,尤其是以 PSR 为核心的规范,是构建高质量、可维护和专业 PHP 应用的基础。它促进了整个社区的合作和代码互操作性。
- 自动化是基石:充分利用
PHP-CS-Fixer和PHP_CodeSniffer等工具,让它们自动化处理代码风格和大部分潜在错误。 - 遵循 PSR:将 PSR 规范视为你的 PHP 开发圣经,尤其关注 PSR-12 和 PSR-4。
- 类型提示:积极使用 PHP 7+ 提供的类型提示功能,并结合
declare(strict_types=1);提高代码的健壮性。 - 编写 PHPDoc:为所有公共 API 编写清晰的 PHPDoc,提高代码的可理解性和 IDE 支持。
- 清晰与简洁:始终以提高代码可读性为目标,编写简洁、明确的代码。
通过持续学习和实践这些规范,你的 PHP 代码将更加专业、易于协作,并能更好地融入现代 PHP 生态系统。
