extract() 核心功能
將關聯陣列的鍵值對匯入當前符號表,鍵名變為變數名,值變為變數值。常用於表單處理、模板渲染、配置載入。
<?php
// 基本用法
$_POST = ['username' => 'john', 'email' => 'john@example.com'];
extract($_POST);
echo $username; // john
echo $email; // john@example.com
參數詳解
int extract(array $array, int $flags = EXTR_OVERWRITE, string $prefix = '')
旗標常數 ($flags)
| 常數 | 行為 | 適用場景 |
EXTR_OVERWRITE | 衝突時覆蓋既有變數 (預設) | 一般用途 |
EXTR_SKIP | 衝突時跳過,保留既有變數 | 保護核心變數不被覆蓋 |
EXTR_PREFIX_SAME | 衝突時加前綴 $prefix_key | 區分來源,避免覆蓋 |
EXTR_PREFIX_ALL | 所有變數加前綴 | 命名空間隔離、模板變數 |
EXTR_PREFIX_INVALID | 僅非法/數字鍵名加前綴 | 數值索引陣列轉變數 |
EXTR_IF_EXISTS | 僅覆蓋已存在的變數 | 預先定義白名單變數 |
EXTR_PREFIX_IF_EXISTS | 已存在變數加前綴建立新變數 | 保留原值並建立備份 |
EXTR_REFS | 以參考方式匯入 (修改變數影響原陣列) | 需同步修改原陣列 |
實戰應用場景
1. 表單處理 (搭配 EXTR_SKIP 保護)
<?php
// 預先定義預設值/白名單
$username = $email = $age = '';
$allowed = ['username', 'email', 'age'];
// 只匯入允許的欄位,不覆蓋預設值
$input = array_intersect_key($_POST, array_flip($allowed));
extract($input, EXTR_SKIP);
// 現在 $username, $email, $age 安全可用
// 惡意提交 $_POST['is_admin']=1 也不會建立 $is_admin
2. 模板引擎變數注入
<?php
function render($template, $data) {
// 所有模板變數加上 tpl_ 前綴,避免污染區域變數
extract($data, EXTR_PREFIX_ALL, 'tpl');
include $template;
}
// template.php
// 可用 $tpl_title, $tpl_content, $tpl_user
// 不會與 $title, $content 衝突
3. 配置檔載入
<?php
// config.php 回傳陣列
return [
'db_host' => 'localhost',
'db_name' => 'myapp',
'debug' => true
];
// 載入
$config = require 'config.php';
extract($config, EXTR_PREFIX_ALL, 'cfg');
// 使用 $cfg_db_host, $cfg_db_name, $cfg_debug
安全性陷阱與最佳實踐
❌ 危險用法
<?php
// 直接 extract($_GET) 或 extract($_REQUEST) - 極度危險!
// 攻擊者可注入任意變數:?config_path=/etc/passwd
// 覆蓋 $config_path 導致檔案包含漏洞
extract($_POST); // 未驗證欄位,任意變數注入
✅ 安全模式
- 白名單過濾:
extract(array_intersect_key($_POST, array_flip($allowed)))
- 使用前綴:
EXTR_PREFIX_ALL 隔離命名空間
- 避免 EXTR_OVERWRITE:預設行為會覆蓋既有變數,改用
EXTR_SKIP
- 不處理不可信資料:
$_GET, $_REQUEST, $_COOKIE 絕不直接 extract
- 關閉 register_globals:PHP 5.4+ 已移除,但舊代碼遺風需清理
效能考量
- extract() 修改符號表,對 OPcache 最佳化有負面影響 (無法靜態分析變數)
- 高頻呼叫路徑 (如模板渲染迴圈) 建議改用
$data['key'] 直接存取
- 大型陣列 extract 記憶體開銷大 (複製變數值)
替代方案比較
| 方式 | 優點 | 缺點 | 建議場景 |
| extract() | 程式碼簡潔、變數直接存取 | 安全風險、OPcache 不友善、除錯困難 | 受控環境配置載入、白名單表單 |
$arr['key'] | 明確、安全、靜態分析友善 | 稍顯冗長 | 通用推薦 |
compact() | 反向操作、明確變數列表 | 需預先定義變數 | 模板資料準備、API 回應建構 |
物件屬性 $obj->key | 型別提示、IDE 支援、封裝邏輯 | 需定義類別 | 領域模型、DTO、大型專案 |