統一代碼風格能顯著降低認知負荷、減少合併衝突、提升團隊協作效率。本文整理一套兼容 **PSR-12** 的 PHP 編程規範,涵蓋命名、縮排、空格、花括號、聲明嚴格類型、註釋、SQL 安全等核心規則,並提供 PHP_CodeSniffer 自動檢查配置。
| 類型 | 規範 | 正例 | 反例 |
|---|---|---|---|
| 類/介面/Trait/Enum | PascalCase | UserService, LoggerInterface | user_service, User_Service |
| 方法/函數 | camelCase | getUserById, calculateTotal | get_user_by_id, GetUserById |
| 常量 | UPPER_SNAKE_CASE | MAX_RETRY_COUNT, DEFAULT_LOCALE | MaxRetryCount |
| 屬性/變數/參數 | camelCase | $userName, $maxRetryCount | $user_name, $MaxRetry |
| 私有/受保護屬性 | camelCase + 前綴 `_` (可選) | $_cache, $_db | $_Cache, $cache_ |
| 全局變數 (極少用) | $g_ 前綴 + camelCase | $g_config | $G_CONFIG |
| 臨時變數 (循環計數) | $i, $j, $k 或語義化 | $i, $userIndex | $index_i |
<?php
declare(strict_types=1);
namespace App\Service;
use App\Entity\User;
use Psr\Log\LoggerInterface;
final class UserService
{
// 1. 常量
public const MAX_LOGIN_ATTEMPTS = 5;
// 2. 屬性 (public → protected → private)
private LoggerInterface $logger;
private int $attempts = 0;
// 3. 建構子
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
// 4. 公共方法
public function register(string $email, string $password): User {
// ...
}
// 5. 受保護方法
protected function validateEmail(string $email): bool {
// ...
}
// 6. 私有方法
private function hashPassword(string $password): string {
// ...
}
}
?>
<?php
// 多行參數
public function create(
string $name,
string $email,
?string $phone = null,
array $tags = [],
): UserEntity {
// ...
}
// 閉包
$users = array_filter($all, fn(User $u) => $u->isActive());
?>
<?php
if ($a === $b) {
foo();
} elseif ($a > $b) {
bar();
} else {
baz();
}
switch ($action) {
case 'create':
$this->create();
break;
case 'delete':
$this->delete();
// no break
default:
throw new InvalidArgumentException("Unknown action: $action");
}
?>
<?php
$config = [
'host' => '127.0.0.1',
'port' => 3306,
'options' => [
'timeout' => 5,
],
];
$sql = <<
<?php
/**
* 使用者註冊服務
*
* @package App\Service
* @see UserRepository
*/
class UserService
{
/**
* 註冊新用戶
*
* @param string $email 郵箱 (唯一)
* @param string $password 明文密碼 (長度 8-72)
* @return UserEntity 已持久化的實體
* @throws ValidationException 郵箱已存在或密碼不符合策略
* @psalm-param non-empty-string $email
* @psalm-param non-empty-string $password
*/
public function register(string $email, string $password): UserEntity
{
// ...
}
}
?>
<?php
$sql = << :since
ORDER BY u.`id` DESC
LIMIT :limit
SQL;
$stmt = $pdo->prepare($sql);
$stmt->execute([
':status' => 'active',
':since' => '2024-01-01',
':limit' => 20,
]);
?>
# 安裝
composer require --dev squizlabs/php_codesniffer friendsofphp/php-cs-fixer
# 專案根目錄 .phpcs.xml (PSR-12 規則集)
*/vendor/*
*/migrations/*
# .php-cs-fixer.php
in(__DIR__)
->exclude('vendor')
->exclude('var')
->name('*.php');
return (new PhpCsFixer\Config())
->setRules([
'@PSR12' => true,
'strict_param' => true,
'phpdoc_align' => ['align' => 'vertical'],
'array_syntax' => ['syntax' => 'short'],
'no_unused_imports' => true,
'ordered_imports' => ['sort_algorithm' => 'alpha'],
])
->setFinder($finder);
# 執行檢查
vendor/bin/phpcs src/
vendor/bin/php-cs-fixer fix --dry-run --diff
# CI 整合 (GitHub Actions)
- name: Code Style
run: vendor/bin/phpcs src/ && vendor/bin/php-cs-fixer fix --dry-run --diff
composer require --dev phpstan/phpstan vimeo/psalm
# phpstan.neon
parameters:
level: 5
paths: [src]
# psalm.xml
# package.json (需 Node 環境) 或用 PHP 版 pre-commit
# composer require --dev captainhook/captainhook
# captainhook.json
{
"pre-commit": {
"enabled": true,
"actions": [
{"action": "phpcs", "options": {"dir": "src"}},
{"action": "phpstan", "options": {"configuration": "phpstan.neon"}}
]
}
}
遵循本規範 + 自動化工具鏈,**代碼風格爭議歸零、低級錯誤攔截率 90%+、新成員上手零成本**。