PHP 現代特性速查 寫出更簡潔安全的代碼(中篇)
PHP 現代特性速查 寫出更簡潔安全的代碼(中篇)
三部曲第二篇,如果講怎么用現代 PHP 特性讓代碼更安全、更快、更好維護。上篇講了 attributes、命名參數、構造器屬性提升、類型化屬性、enums、只讀 DTO 和一等公民可調用對象。默認你已經看過了——中篇接著往下講。
下面是 10 個實戰特性和慣用法(PHP 7.1 → 8.x),每個都有例子、效果和使用場景。寫給想直接上手的人——不是語言八卦。
Match 表達式 — 更智能、更安全的 switch
替代了什么:冗長易錯的 switch 和意外 fall-through。
什么時候用:值映射、分支返回、替代多 case 的 switch。
// 輸入
$statusCode = 404;
// 使用 match (PHP 8.0+)
$statusText = match ($statusCode) {
200 => 'OK',
201 => 'Created',
400, 422 => 'Client Error',
404 => 'Not Found',
default => 'Unknown',
};
echo $statusText; // 輸出: "Not Found"
好在哪:
- 表達式直接返回值,不用臨時變量
- 嚴格比較(
===)不會類型轉換 - 沒有 fall-through,每個分支必須有返回
注意:match 用 === 比較——類型要對上。
Null-safe 操作符 (?->) — 安全鏈式調用
替代了什么:isset() 或 optional() 包裝的長鏈式調用。
什么時候用:讀嵌套對象,值可能缺失且返回 null 是合理的。
$user = null;
$country = $user?->profile?->address?->country;
var_dump($country); // 輸出: null
好在哪:少寫判斷,避免 Call to a member function on null 異常。service 層、DTO 映射、Blade 模板都能用,意圖清楚。
注意:?-> 只讀;不能用在數組上,可能掩蓋數據模型問題——確定值可能缺失時再用。
Spread 運算符 (...) — 數組合并
替代了什么:冗長的 array_merge() 和手動復制。
什么時候用:合并配置、默認值覆蓋、拼接數組。
$defaults = ['color' => 'blue', 'size' => 'M'];
$overrides = ['color' => 'red'];
$config = [...$defaults, ...$overrides];
print_r($config);
// 輸出: ['color' => 'red', 'size' => 'M']
好在哪:語義清楚,保留鍵,后面的覆蓋前面的。PHP 7.4+ 可用。
注意:只合并一層——嵌套數組要用其他辦法。
Variadic 參數和解包 — 靈活參數
替代了什么:笨拙的參數列表和手動轉發。
什么時候用:包裝函數、日志輔助、函數組合。
function sum(int ...$numbers): int {
return array_sum($numbers);
}
echo sum(1,2,3); // 輸出: 6
// 數組解包成參數
$args = [4,5,6];
echo sum(...$args); // 輸出: 15
生成器(Generators)— 惰性迭代省內存
替代了什么:Model::all() 或 file() 把大數據集全加載到內存。
什么時候用:流式 CSV 導出、處理日志、分頁/分塊數據。
function readLargeCsv(string $path): Generator {
$handle = fopen($path, 'r');
while (($line = fgetcsv($handle)) !== false) {
yield $line;
}
fclose($handle);
}
// 用法
foreach (readLargeCsv('big.csv') as $row) {
// 處理行,不會把整個文件加載到內存
}
好在哪:內存占用恒定;后臺任務和 CLI 腳本必備。
注意:generators 序列化不一樣;隊列任務要轉換一下。
解構賦值(Destructuring)— 快速提取
替代了什么:函數返回數組時冗長的索引訪問。
什么時候用:返回多個值、解析 DB 行、配置元組。
function queryStats(): array {
return ['total' => 100, 'failed' => 2];
}
['total' => $t, 'failed' => $f] = queryStats();
echo "$t / $f"; // 輸出: "100 / 2"
// 數字列表解構
[$a, $b] = [1, 2];
好在哪:綁定清楚,少用中間變量。PHP 7.1+ 可用。
命名構造器(Named Constructors)— 明確構造
替代了什么:模糊的 new 表達式、不一致的對象狀態。
什么時候用:構造函數有歧義或要表達意圖時(如 fromArray、fromCredentials)。
class Money {
private function __construct(private int $cents) {}
public static function fromFloat(float $amount): self {
return new self((int) round($amount * 100));
}
public static function fromCents(int $cents): self {
return new self($cents);
}
}
$m = Money::fromFloat(12.34);
// 輸出: Money 實例,表示 1234 分
好在哪:創建方式自解釋,支持多種構造方法,驗證集中。
assert() — 快速失敗檢查(僅開發)
替代了什么:靜默的無效狀態,后來變成難查的 bug。
什么時候用:開發模式檢查、關鍵路徑的契約假設。
// 僅開發: 確保值是 int
assert(is_int($count), 'count must be int');
好在哪:開銷小、表達清楚的快速失敗。php.ini 配置 zend.assertions=1 和 assert.exception=1 讓開發環境拋異常。
注意:別在生產用 assert() 驗證——能被禁用;用類型化屬性和顯式檢查保證運行時安全。
特質(Traits)— 不用繼承的代碼復用
替代了什么:不相關類之間重復的輔助方法。
什么時候用:共享行為(日志輔助、小工具),繼承不合適的地方。
trait LoggerTrait {
public function log(string $msg): void {
// 簡單日志
error_log($msg);
}
}
class PaymentService {
use LoggerTrait;
public function pay() { $this->log("paying"); }
}
好在哪:復用代碼,不用深層繼承。
注意:traits 容易變垃圾場——保持專注和小型,避免緊耦合。
匿名類(Anonymous Classes)— 一次性對象
替代了什么:只在一個地方或測試中用的小輔助類。
什么時候用:測試 stub、輕量級策略對象。
// 快速創建實現
$repo = new class implements UserRepoInterface {
public function find(int $id) { return null; }
};
好在哪:少建文件,單個作用域內提供強類型對象。測試替身好用。
組合使用:真實例子
假設 CLI 任務流式處理訂單、轉換后寫入 S3。組合生成器、命名構造器、可變參數和 match:
function streamOrders(Generator $src): Generator {
foreach ($src as $row) {
yield Order::fromArray($row); // named ctor
}
}
// 管道
$orders = streamOrders(readCsv('orders.csv'));
foreach ($orders as $order) {
$status = match ($order->state) {
'paid' => 'processing',
'cancelled' => 'archived',
default => 'pending'
};
// 批量上傳 S3 (variadic helper)
batchUpload(...$order->toParts());
}
這種寫法省內存、意圖明確、可組合。
快速參考 — 什么時候用
| 特性 | 使用場景 |
|---|---|
| match | 值映射,更安全的 switch |
| ?-> | 讀嵌套可選屬性 |
| ... (spread) | 合并配置或數組 |
| 可變參數 | 轉發參數、builder API |
| 生成器 | 處理大數據流 |
| 解構賦值 | 快速綁定多個返回值 |
| 命名構造器 | 清晰的對象創建 |
| assert | 開發環境契約檢查 |
| 特質 | 共享專注行為 |
| 匿名類 | 測試替身 / 一次性對象 |
結語
中篇講了現代 PHP 特性怎么讓代碼更有表達力、更安全、更省內存。這些不是玩具——用好了能簡化推理、減少樣板代碼。
下篇(第三篇):高級應用模式——依賴注入最佳實踐、零停機遷移、性能微優化、生成器、纖程、生產就緒速查表。

浙公網安備 33010602011771號