universal-dev-standards 6.14.0-beta.2 → 6.14.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/ai/standards/ai-response-navigation.ai.yaml +43 -3
- package/bundled/ai/standards/checkin-standards.ai.yaml +25 -6
- package/bundled/ai/standards/open-work-tracking.ai.yaml +4 -1
- package/bundled/ai/standards/pipeline-security-gates.ai.yaml +5 -1
- package/bundled/core/ai-response-navigation.md +128 -12
- package/bundled/core/open-work-tracking.md +1 -1
- package/bundled/extensions/frameworks/fat-free-patterns.md +937 -0
- package/bundled/extensions/languages/csharp-style.md +464 -0
- package/bundled/extensions/languages/php/fat-free-patterns.md +915 -0
- package/bundled/extensions/languages/php/php-style.md +693 -0
- package/bundled/extensions/languages/php-style.md +700 -0
- package/bundled/extensions/locales/zh-cn.md +717 -0
- package/bundled/extensions/locales/zh-tw.md +717 -0
- package/bundled/locales/COVERAGE.md +5 -4
- package/bundled/locales/zh-CN/CHANGELOG.md +44 -3
- package/bundled/locales/zh-CN/README.md +2 -2
- package/bundled/locales/zh-CN/SECURITY.md +1 -1
- package/bundled/locales/zh-CN/core/ai-response-navigation.md +110 -12
- package/bundled/locales/zh-CN/skills/README.md +1 -0
- package/bundled/locales/zh-CN/skills/comprehension-ladder/SKILL.md +289 -0
- package/bundled/locales/zh-CN/skills/comprehension-ladder/eval-cases.md +261 -0
- package/bundled/locales/zh-TW/CHANGELOG.md +44 -3
- package/bundled/locales/zh-TW/README.md +2 -2
- package/bundled/locales/zh-TW/SECURITY.md +1 -1
- package/bundled/locales/zh-TW/core/ai-response-navigation.md +110 -12
- package/bundled/locales/zh-TW/core/open-work-tracking.md +3 -3
- package/bundled/locales/zh-TW/skills/README.md +1 -0
- package/bundled/locales/zh-TW/skills/comprehension-ladder/SKILL.md +289 -0
- package/bundled/locales/zh-TW/skills/comprehension-ladder/eval-cases.md +261 -0
- package/bundled/skills/README.md +1 -0
- package/bundled/skills/comprehension-ladder/SKILL.md +283 -0
- package/bundled/skills/comprehension-ladder/eval-cases.md +255 -0
- package/package.json +2 -2
- package/src/commands/check.js +9 -0
- package/src/commands/init.js +100 -27
- package/src/commands/uninstall.js +144 -30
- package/src/commands/update.js +62 -3
- package/src/core/install-records.js +191 -0
- package/src/i18n/messages.js +39 -6
- package/src/installers/hooks-installer.js +61 -30
- package/src/installers/integration-installer.js +5 -1
- package/src/installers/standards-installer.js +16 -23
- package/src/reconciler/plan-executor.js +10 -11
- package/src/uninstallers/hook-uninstaller.js +219 -33
- package/src/uninstallers/integration-uninstaller.js +35 -5
- package/src/utils/copier.js +57 -0
- package/src/utils/git-hooks.js +139 -7
- package/src/utils/hasher.js +36 -0
- package/src/utils/integration-generator.js +16 -6
- package/src/utils/legacy-hook-migration.js +112 -0
- package/src/utils/locale.js +19 -0
- package/src/utils/open-work-tracking.mjs +124 -23
- package/standards-registry.json +21 -7
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
# PHP Coding Style Guide
|
|
2
|
+
# PHP 程式碼風格指南
|
|
3
|
+
|
|
4
|
+
**Version**: 1.0.0
|
|
5
|
+
**Last Updated**: 2025-12-22
|
|
6
|
+
**Applicability**: All PHP projects
|
|
7
|
+
**適用範圍**: 所有 PHP 專案
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Purpose | 目的
|
|
12
|
+
|
|
13
|
+
This guide defines PHP coding conventions based on PSR-12 to ensure consistent, readable, and maintainable code across the team.
|
|
14
|
+
|
|
15
|
+
本指南基於 PSR-12 定義 PHP 編碼慣例,確保團隊程式碼的一致性、可讀性與可維護性。
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Standards Compliance | 標準遵循
|
|
20
|
+
|
|
21
|
+
This guide follows:
|
|
22
|
+
- **PSR-1**: Basic Coding Standard
|
|
23
|
+
- **PSR-12**: Extended Coding Style (supersedes PSR-2)
|
|
24
|
+
- **PSR-4**: Autoloading Standard
|
|
25
|
+
|
|
26
|
+
本指南遵循:
|
|
27
|
+
- **PSR-1**: 基本編碼標準
|
|
28
|
+
- **PSR-12**: 擴展編碼風格(取代 PSR-2)
|
|
29
|
+
- **PSR-4**: 自動載入標準
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Naming Conventions | 命名慣例
|
|
34
|
+
|
|
35
|
+
### Summary Table | 總覽表
|
|
36
|
+
|
|
37
|
+
| Element | Style | Example |
|
|
38
|
+
|---------|-------|---------|
|
|
39
|
+
| Namespace | PascalCase | `App\Services` |
|
|
40
|
+
| Class | PascalCase | `UserService` |
|
|
41
|
+
| Interface | PascalCase + Suffix | `UserRepositoryInterface` |
|
|
42
|
+
| Trait | PascalCase + Suffix | `LoggableTrait` |
|
|
43
|
+
| Method | camelCase | `getUserById` |
|
|
44
|
+
| Property | camelCase | `$userName` |
|
|
45
|
+
| Private Property | camelCase | `$userName` (no underscore prefix) |
|
|
46
|
+
| Constant | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` |
|
|
47
|
+
| Variable | camelCase | `$currentUser` |
|
|
48
|
+
| Function (global) | snake_case | `array_map` |
|
|
49
|
+
|
|
50
|
+
### Detailed Rules | 詳細規則
|
|
51
|
+
|
|
52
|
+
#### Classes & Interfaces | 類別與介面
|
|
53
|
+
|
|
54
|
+
```php
|
|
55
|
+
<?php
|
|
56
|
+
|
|
57
|
+
namespace App\Services;
|
|
58
|
+
|
|
59
|
+
// ✅ 正確
|
|
60
|
+
class UserService
|
|
61
|
+
{
|
|
62
|
+
// ...
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface UserRepositoryInterface
|
|
66
|
+
{
|
|
67
|
+
// ...
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
trait LoggableTrait
|
|
71
|
+
{
|
|
72
|
+
// ...
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ❌ 錯誤
|
|
76
|
+
class userService { } // 應使用 PascalCase
|
|
77
|
+
interface IUserRepository { } // PHP 慣例不使用 I 前綴
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### Properties & Methods | 屬性與方法
|
|
81
|
+
|
|
82
|
+
```php
|
|
83
|
+
<?php
|
|
84
|
+
|
|
85
|
+
class UserService
|
|
86
|
+
{
|
|
87
|
+
// ✅ 正確
|
|
88
|
+
private UserRepository $userRepository;
|
|
89
|
+
protected string $connectionName;
|
|
90
|
+
public int $retryCount = 0;
|
|
91
|
+
|
|
92
|
+
public function getUserById(int $userId): ?User
|
|
93
|
+
{
|
|
94
|
+
return $this->userRepository->find($userId);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ❌ 錯誤
|
|
98
|
+
private $_userRepository; // 不使用底線前綴
|
|
99
|
+
public function GetUserById() { } // 方法應使用 camelCase
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Constants | 常數
|
|
104
|
+
|
|
105
|
+
```php
|
|
106
|
+
<?php
|
|
107
|
+
|
|
108
|
+
class Configuration
|
|
109
|
+
{
|
|
110
|
+
// ✅ 正確
|
|
111
|
+
public const MAX_RETRY_COUNT = 3;
|
|
112
|
+
public const DEFAULT_TIMEOUT = 30;
|
|
113
|
+
private const CACHE_PREFIX = 'app_';
|
|
114
|
+
|
|
115
|
+
// ❌ 錯誤
|
|
116
|
+
public const maxRetryCount = 3; // 應使用 UPPER_SNAKE_CASE
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## File Structure | 檔案結構
|
|
123
|
+
|
|
124
|
+
### PHP File Format | PHP 檔案格式
|
|
125
|
+
|
|
126
|
+
```php
|
|
127
|
+
<?php
|
|
128
|
+
// 1. 嚴格模式宣告(必須)
|
|
129
|
+
declare(strict_types=1);
|
|
130
|
+
|
|
131
|
+
// 2. 命名空間宣告
|
|
132
|
+
namespace App\Services;
|
|
133
|
+
|
|
134
|
+
// 3. use 匯入(按類型分組,字母排序)
|
|
135
|
+
use App\Contracts\UserRepositoryInterface;
|
|
136
|
+
use App\Models\User;
|
|
137
|
+
use Psr\Log\LoggerInterface;
|
|
138
|
+
|
|
139
|
+
// 4. 類別宣告
|
|
140
|
+
class UserService
|
|
141
|
+
{
|
|
142
|
+
// ...
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Use Statement Organization | Use 語句組織
|
|
147
|
+
|
|
148
|
+
```php
|
|
149
|
+
<?php
|
|
150
|
+
|
|
151
|
+
declare(strict_types=1);
|
|
152
|
+
|
|
153
|
+
namespace App\Http\Controllers;
|
|
154
|
+
|
|
155
|
+
// 1. PHP 內建類別
|
|
156
|
+
use Exception;
|
|
157
|
+
use InvalidArgumentException;
|
|
158
|
+
|
|
159
|
+
// 2. 框架/第三方類別
|
|
160
|
+
use Illuminate\Http\Request;
|
|
161
|
+
use Illuminate\Http\Response;
|
|
162
|
+
|
|
163
|
+
// 3. 專案內部類別
|
|
164
|
+
use App\Services\UserService;
|
|
165
|
+
use App\Models\User;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Code Structure | 程式碼結構
|
|
171
|
+
|
|
172
|
+
### Method Length | 方法長度
|
|
173
|
+
|
|
174
|
+
- **Maximum**: 50 lines (excluding blank lines and comments)
|
|
175
|
+
- **Recommended**: 20-30 lines
|
|
176
|
+
- **最大**: 50 行(不含空行與註解)
|
|
177
|
+
- **建議**: 20-30 行
|
|
178
|
+
|
|
179
|
+
```php
|
|
180
|
+
<?php
|
|
181
|
+
|
|
182
|
+
// ✅ 正確:拆分成多個小方法
|
|
183
|
+
public function processOrder(Order $order): OrderResult
|
|
184
|
+
{
|
|
185
|
+
$this->validateOrder($order);
|
|
186
|
+
$items = $this->prepareItems($order);
|
|
187
|
+
$total = $this->calculateTotal($items);
|
|
188
|
+
return $this->createOrderResult($order, $items, $total);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ❌ 錯誤:方法過長,應該拆分
|
|
192
|
+
public function processOrder(Order $order): OrderResult
|
|
193
|
+
{
|
|
194
|
+
// ... 超過 50 行的程式碼 ...
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Nesting Depth | 巢狀深度
|
|
199
|
+
|
|
200
|
+
- **Maximum**: 3 levels
|
|
201
|
+
- **Recommended**: 2 levels
|
|
202
|
+
- **最大**: 3 層
|
|
203
|
+
- **建議**: 2 層
|
|
204
|
+
|
|
205
|
+
```php
|
|
206
|
+
<?php
|
|
207
|
+
|
|
208
|
+
// ✅ 正確:使用 early return 減少巢狀
|
|
209
|
+
public function getActiveUser(int $userId): ?User
|
|
210
|
+
{
|
|
211
|
+
$user = $this->userRepository->find($userId);
|
|
212
|
+
if ($user === null) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (!$user->isActive()) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return $user;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ❌ 錯誤:巢狀過深
|
|
224
|
+
public function getActiveUser(int $userId): ?User
|
|
225
|
+
{
|
|
226
|
+
$user = $this->userRepository->find($userId);
|
|
227
|
+
if ($user !== null) {
|
|
228
|
+
if ($user->isActive()) {
|
|
229
|
+
if ($user->isVerified()) {
|
|
230
|
+
if ($user->hasPermission()) { // 第 4 層巢狀
|
|
231
|
+
return $user;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Type Declarations | 型別宣告
|
|
243
|
+
|
|
244
|
+
### Strict Types | 嚴格型別
|
|
245
|
+
|
|
246
|
+
All PHP files MUST declare strict types.
|
|
247
|
+
所有 PHP 檔案必須宣告嚴格型別。
|
|
248
|
+
|
|
249
|
+
```php
|
|
250
|
+
<?php
|
|
251
|
+
|
|
252
|
+
declare(strict_types=1); // 必須在檔案第一行
|
|
253
|
+
|
|
254
|
+
namespace App\Services;
|
|
255
|
+
|
|
256
|
+
class UserService
|
|
257
|
+
{
|
|
258
|
+
// 參數型別、回傳型別必須明確
|
|
259
|
+
public function getUserById(int $userId): ?User
|
|
260
|
+
{
|
|
261
|
+
// ...
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 使用聯合型別 (PHP 8.0+)
|
|
265
|
+
public function findUser(int|string $identifier): ?User
|
|
266
|
+
{
|
|
267
|
+
// ...
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 使用 nullable 型別
|
|
271
|
+
public function getEmail(): ?string
|
|
272
|
+
{
|
|
273
|
+
return $this->email;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Property Types | 屬性型別
|
|
279
|
+
|
|
280
|
+
```php
|
|
281
|
+
<?php
|
|
282
|
+
|
|
283
|
+
declare(strict_types=1);
|
|
284
|
+
|
|
285
|
+
class User
|
|
286
|
+
{
|
|
287
|
+
// ✅ 正確:使用型別宣告 (PHP 7.4+)
|
|
288
|
+
private int $id;
|
|
289
|
+
private string $name;
|
|
290
|
+
private ?string $email = null;
|
|
291
|
+
private bool $isActive = true;
|
|
292
|
+
private array $roles = [];
|
|
293
|
+
|
|
294
|
+
// ❌ 錯誤:缺少型別宣告
|
|
295
|
+
private $id;
|
|
296
|
+
private $name;
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Documentation | 文件註解
|
|
303
|
+
|
|
304
|
+
### PHPDoc Standards | PHPDoc 標準
|
|
305
|
+
|
|
306
|
+
```php
|
|
307
|
+
<?php
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 使用者服務類別
|
|
311
|
+
*
|
|
312
|
+
* 處理使用者相關的業務邏輯,包括查詢、建立、更新使用者資料。
|
|
313
|
+
*/
|
|
314
|
+
class UserService
|
|
315
|
+
{
|
|
316
|
+
/**
|
|
317
|
+
* 根據使用者 ID 取得使用者資訊
|
|
318
|
+
*
|
|
319
|
+
* @param int $userId 使用者的唯一識別碼
|
|
320
|
+
* @return User|null 使用者實體,若不存在則回傳 null
|
|
321
|
+
* @throws InvalidArgumentException 當 userId 為負數時拋出
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* $user = $userService->getUserById(123);
|
|
325
|
+
* if ($user !== null) {
|
|
326
|
+
* echo $user->getName();
|
|
327
|
+
* }
|
|
328
|
+
*/
|
|
329
|
+
public function getUserById(int $userId): ?User
|
|
330
|
+
{
|
|
331
|
+
if ($userId < 0) {
|
|
332
|
+
throw new InvalidArgumentException('User ID must be non-negative');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return $this->userRepository->find($userId);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Comment Language | 註解語言
|
|
341
|
+
|
|
342
|
+
- **PHPDoc**: Traditional Chinese (繁體中文)
|
|
343
|
+
- **Inline Comments**: Traditional Chinese (繁體中文)
|
|
344
|
+
- **TODO/FIXME**: English with Traditional Chinese description
|
|
345
|
+
|
|
346
|
+
```php
|
|
347
|
+
<?php
|
|
348
|
+
|
|
349
|
+
// ✅ 正確
|
|
350
|
+
/** @var User 當前使用者 */
|
|
351
|
+
private User $currentUser;
|
|
352
|
+
|
|
353
|
+
// 檢查使用者是否有權限
|
|
354
|
+
if ($this->hasPermission($user)) {
|
|
355
|
+
// 處理授權邏輯
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// TODO: Implement caching - 需實作快取機制以提升效能
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## Security Best Practices | 安全性最佳實踐
|
|
364
|
+
|
|
365
|
+
### SQL Injection Prevention | SQL 注入防護
|
|
366
|
+
|
|
367
|
+
```php
|
|
368
|
+
<?php
|
|
369
|
+
|
|
370
|
+
// ❌ 危險:直接串接 SQL
|
|
371
|
+
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];
|
|
372
|
+
$result = $db->query($sql);
|
|
373
|
+
|
|
374
|
+
// ✅ 正確:使用參數化查詢
|
|
375
|
+
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
|
|
376
|
+
$stmt->execute([$userId]);
|
|
377
|
+
$result = $stmt->fetch();
|
|
378
|
+
|
|
379
|
+
// ✅ 正確:使用 PDO 命名參數
|
|
380
|
+
$stmt = $db->prepare("SELECT * FROM users WHERE email = :email");
|
|
381
|
+
$stmt->execute(['email' => $email]);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### XSS Prevention | XSS 防護
|
|
385
|
+
|
|
386
|
+
```php
|
|
387
|
+
<?php
|
|
388
|
+
|
|
389
|
+
// ❌ 危險:直接輸出使用者輸入
|
|
390
|
+
echo $_GET['name'];
|
|
391
|
+
|
|
392
|
+
// ✅ 正確:使用 htmlspecialchars
|
|
393
|
+
echo htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
|
|
394
|
+
|
|
395
|
+
// ✅ 正確:使用框架的 escape 函式
|
|
396
|
+
echo e($name); // Laravel
|
|
397
|
+
echo $this->escape($name); // 其他框架
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Password Handling | 密碼處理
|
|
401
|
+
|
|
402
|
+
```php
|
|
403
|
+
<?php
|
|
404
|
+
|
|
405
|
+
// ❌ 錯誤:使用 MD5 或 SHA1
|
|
406
|
+
$hash = md5($password);
|
|
407
|
+
$hash = sha1($password);
|
|
408
|
+
|
|
409
|
+
// ✅ 正確:使用 password_hash
|
|
410
|
+
$hash = password_hash($password, PASSWORD_DEFAULT);
|
|
411
|
+
|
|
412
|
+
// ✅ 正確:驗證密碼
|
|
413
|
+
if (password_verify($inputPassword, $storedHash)) {
|
|
414
|
+
// 密碼正確
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Input Validation | 輸入驗證
|
|
419
|
+
|
|
420
|
+
```php
|
|
421
|
+
<?php
|
|
422
|
+
|
|
423
|
+
// ✅ 正確:驗證和過濾輸入
|
|
424
|
+
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
|
|
425
|
+
if ($email === false) {
|
|
426
|
+
throw new InvalidArgumentException('Invalid email format');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
$userId = filter_var($_GET['id'], FILTER_VALIDATE_INT);
|
|
430
|
+
if ($userId === false || $userId < 0) {
|
|
431
|
+
throw new InvalidArgumentException('Invalid user ID');
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Error Handling | 錯誤處理
|
|
438
|
+
|
|
439
|
+
### Exception Handling | 例外處理
|
|
440
|
+
|
|
441
|
+
```php
|
|
442
|
+
<?php
|
|
443
|
+
|
|
444
|
+
// ❌ 禁止:空的 catch 區塊
|
|
445
|
+
try {
|
|
446
|
+
$this->processOrder($order);
|
|
447
|
+
} catch (Exception $e) {
|
|
448
|
+
// 吞掉例外,不處理
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ✅ 正確:適當處理例外
|
|
452
|
+
try {
|
|
453
|
+
$this->processOrder($order);
|
|
454
|
+
} catch (ValidationException $e) {
|
|
455
|
+
$this->logger->warning('Validation failed', [
|
|
456
|
+
'order_id' => $order->getId(),
|
|
457
|
+
'errors' => $e->getErrors(),
|
|
458
|
+
]);
|
|
459
|
+
throw $e;
|
|
460
|
+
} catch (Exception $e) {
|
|
461
|
+
$this->logger->error('Order processing failed', [
|
|
462
|
+
'order_id' => $order->getId(),
|
|
463
|
+
'exception' => $e->getMessage(),
|
|
464
|
+
]);
|
|
465
|
+
throw new OrderProcessingException('Failed to process order', 0, $e);
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Custom Exceptions | 自定義例外
|
|
470
|
+
|
|
471
|
+
```php
|
|
472
|
+
<?php
|
|
473
|
+
|
|
474
|
+
declare(strict_types=1);
|
|
475
|
+
|
|
476
|
+
namespace App\Exceptions;
|
|
477
|
+
|
|
478
|
+
use Exception;
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* 訂單處理例外
|
|
482
|
+
*/
|
|
483
|
+
class OrderProcessingException extends Exception
|
|
484
|
+
{
|
|
485
|
+
private array $context;
|
|
486
|
+
|
|
487
|
+
public function __construct(
|
|
488
|
+
string $message,
|
|
489
|
+
array $context = [],
|
|
490
|
+
int $code = 0,
|
|
491
|
+
?Exception $previous = null
|
|
492
|
+
) {
|
|
493
|
+
parent::__construct($message, $code, $previous);
|
|
494
|
+
$this->context = $context;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
public function getContext(): array
|
|
498
|
+
{
|
|
499
|
+
return $this->context;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## Prohibited Practices | 禁止行為
|
|
507
|
+
|
|
508
|
+
### 1. Pinyin Naming | 拼音命名
|
|
509
|
+
|
|
510
|
+
```php
|
|
511
|
+
<?php
|
|
512
|
+
|
|
513
|
+
// ❌ 絕對禁止
|
|
514
|
+
class YongHuFuWu { } // 應為 UserService
|
|
515
|
+
function yanZhengQuanXian() { } // 應為 validatePermission
|
|
516
|
+
$baiMingDan = []; // 應為 $whitelist
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### 2. Global Variables | 全域變數
|
|
520
|
+
|
|
521
|
+
```php
|
|
522
|
+
<?php
|
|
523
|
+
|
|
524
|
+
// ❌ 禁止
|
|
525
|
+
global $db;
|
|
526
|
+
$GLOBALS['config'] = [];
|
|
527
|
+
|
|
528
|
+
// ✅ 正確:使用依賴注入
|
|
529
|
+
class UserService
|
|
530
|
+
{
|
|
531
|
+
public function __construct(
|
|
532
|
+
private Database $db,
|
|
533
|
+
private Config $config
|
|
534
|
+
) {}
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 3. Magic Numbers/Strings | 魔術數字/字串
|
|
539
|
+
|
|
540
|
+
```php
|
|
541
|
+
<?php
|
|
542
|
+
|
|
543
|
+
// ❌ 錯誤
|
|
544
|
+
if ($retryCount > 3) { }
|
|
545
|
+
if ($status === 'approved') { }
|
|
546
|
+
|
|
547
|
+
// ✅ 正確
|
|
548
|
+
class OrderStatus
|
|
549
|
+
{
|
|
550
|
+
public const MAX_RETRY_COUNT = 3;
|
|
551
|
+
public const STATUS_APPROVED = 'approved';
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if ($retryCount > OrderStatus::MAX_RETRY_COUNT) { }
|
|
555
|
+
if ($status === OrderStatus::STATUS_APPROVED) { }
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### 4. Suppressing Errors | 抑制錯誤
|
|
559
|
+
|
|
560
|
+
```php
|
|
561
|
+
<?php
|
|
562
|
+
|
|
563
|
+
// ❌ 禁止使用 @ 抑制錯誤
|
|
564
|
+
$value = @$array['key'];
|
|
565
|
+
$result = @file_get_contents($url);
|
|
566
|
+
|
|
567
|
+
// ✅ 正確:明確處理
|
|
568
|
+
$value = $array['key'] ?? null;
|
|
569
|
+
|
|
570
|
+
$result = file_get_contents($url);
|
|
571
|
+
if ($result === false) {
|
|
572
|
+
throw new RuntimeException('Failed to fetch content');
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Code Organization | 程式碼組織
|
|
579
|
+
|
|
580
|
+
### Class Member Order | 類別成員順序
|
|
581
|
+
|
|
582
|
+
```php
|
|
583
|
+
<?php
|
|
584
|
+
|
|
585
|
+
declare(strict_types=1);
|
|
586
|
+
|
|
587
|
+
namespace App\Services;
|
|
588
|
+
|
|
589
|
+
class UserService
|
|
590
|
+
{
|
|
591
|
+
// 1. Constants | 常數
|
|
592
|
+
private const MAX_RETRY_COUNT = 3;
|
|
593
|
+
|
|
594
|
+
// 2. Static properties | 靜態屬性
|
|
595
|
+
private static int $instanceCount = 0;
|
|
596
|
+
|
|
597
|
+
// 3. Instance properties | 實例屬性
|
|
598
|
+
private UserRepository $userRepository;
|
|
599
|
+
private LoggerInterface $logger;
|
|
600
|
+
|
|
601
|
+
// 4. Constructor | 建構子
|
|
602
|
+
public function __construct(
|
|
603
|
+
UserRepository $userRepository,
|
|
604
|
+
LoggerInterface $logger
|
|
605
|
+
) {
|
|
606
|
+
$this->userRepository = $userRepository;
|
|
607
|
+
$this->logger = $logger;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// 5. Public methods | 公開方法
|
|
611
|
+
public function getUserById(int $userId): ?User
|
|
612
|
+
{
|
|
613
|
+
return $this->userRepository->find($userId);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// 6. Protected methods | 受保護方法
|
|
617
|
+
protected function validateUser(User $user): bool
|
|
618
|
+
{
|
|
619
|
+
// ...
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// 7. Private methods | 私有方法
|
|
623
|
+
private function logAccess(int $userId): void
|
|
624
|
+
{
|
|
625
|
+
// ...
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Related Standards | 相關標準
|
|
633
|
+
|
|
634
|
+
- [Anti-Hallucination Standard](../../../core/anti-hallucination.md) - AI 協作防幻覺標準
|
|
635
|
+
- [Code Check-in Standards](../../../core/checkin-standards.md) - 程式碼簽入檢查點標準
|
|
636
|
+
- [Commit Message Guide](../../../core/commit-message-guide.md) - Commit 訊息規範
|
|
637
|
+
- [Fat-Free Framework Patterns](fat-free-patterns.md) - Fat-Free 框架模式
|
|
638
|
+
- [Traditional Chinese Language Guide](../../locales/zh-tw.md) - 繁體中文語言規範
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## Quick Reference Card | 快速參考卡
|
|
643
|
+
|
|
644
|
+
```
|
|
645
|
+
┌─────────────────────────────────────────────────────────┐
|
|
646
|
+
│ PHP Naming Conventions │
|
|
647
|
+
├─────────────────────────────────────────────────────────┤
|
|
648
|
+
│ Class/Interface/Trait │ PascalCase │ UserService │
|
|
649
|
+
│ Method/Property │ camelCase │ getUserById │
|
|
650
|
+
│ Constant │ UPPER_SNAKE │ MAX_COUNT │
|
|
651
|
+
│ Variable │ camelCase │ $currentUser │
|
|
652
|
+
├─────────────────────────────────────────────────────────┤
|
|
653
|
+
│ Requirements │
|
|
654
|
+
├─────────────────────────────────────────────────────────┤
|
|
655
|
+
│ Strict Types │ declare(strict_types=1); │
|
|
656
|
+
│ Type Declarations │ Required for all params/return │
|
|
657
|
+
│ PSR-12 Compliance │ Required │
|
|
658
|
+
├─────────────────────────────────────────────────────────┤
|
|
659
|
+
│ Limits │
|
|
660
|
+
├─────────────────────────────────────────────────────────┤
|
|
661
|
+
│ Method Length │ ≤ 50 lines │
|
|
662
|
+
│ Nesting Depth │ ≤ 3 levels │
|
|
663
|
+
├─────────────────────────────────────────────────────────┤
|
|
664
|
+
│ Prohibited │
|
|
665
|
+
├─────────────────────────────────────────────────────────┤
|
|
666
|
+
│ ❌ Pinyin naming │ yanZhengQuanXian │
|
|
667
|
+
│ ❌ Global variables │ global $db │
|
|
668
|
+
│ ❌ Magic numbers │ if ($x > 3) │
|
|
669
|
+
│ ❌ Error suppression │ @file_get_contents() │
|
|
670
|
+
│ ❌ Empty catch │ catch (Exception $e) { } │
|
|
671
|
+
└─────────────────────────────────────────────────────────┘
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## Version History | 版本歷史
|
|
677
|
+
|
|
678
|
+
| Version | Date | Changes |
|
|
679
|
+
|---------|------|---------|
|
|
680
|
+
| 1.0.0 | 2025-12-22 | Initial PHP style guide based on PSR-12 |
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## License | 授權
|
|
685
|
+
|
|
686
|
+
This standard is released under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
|
687
|
+
|
|
688
|
+
本標準以 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 授權發布。
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
**Maintainer**: Development Team
|
|
693
|
+
**維護者**: 開發團隊
|