func_num_args()、func_get_arg()、func_get_args() 是 PHP 內建的「函數內部」檢查實際傳入參數的函數族,**只能在函數內部調用**,外部直接呼叫會報錯。若需在「外部」(調用前、裝飾器、路由解析、文檔生成)獲取函數定義的參數資訊,必須使用 Reflection API。
<?php
function war($a, $b, $c) {
echo "內部調用 func_num_args(): " . func_num_args() . "\n"; // 3
}
war(1, 2, 3);
// 外部直接調用 → Fatal Error
// echo func_num_args(); // 錯誤:Cannot be used outside of a function
<?php
function war($a, $b, $c = 'default', ...$rest) {}
$ref = new ReflectionFunction('war');
echo "參數總數: " . $ref->getNumberOfParameters() . "\n"; // 4 (a, b, c, ...$rest)
echo "必填參數數: " . $ref->getNumberOfRequiredParameters() . "\n"; // 2 (a, b)
<?php
function apiUserCreate(string $name, int $age = 18, array $tags = [], ?string $note = null) {}
$ref = new ReflectionFunction('apiUserCreate');
foreach ($ref->getParameters() as $param) {
echo "參數名: {$param->getName()}\n";
echo " 是否必填: " . ($param->isOptional() ? '否' : '是') . "\n";
echo " 是否可變參數: " . ($param->isVariadic() ? '是' : '否') . "\n";
echo " 是否傳引用: " . ($param->isPassedByReference() ? '是' : '否') . "\n";
echo " 預設值: " . ($param->isDefaultValueAvailable() ? var_export($param->getDefaultValue(), true) : '無') . "\n";
// 類型提示 (PHP 7+)
$type = $param->getType();
if ($type) {
echo " 類型: " . $type->getName() . ($type->allowsNull() ? '|null' : '') . "\n";
echo " 內建類型: " . ($type->isBuiltin() ? '是' : '否') . "\n";
}
// 屬性 (PHP 8+)
if ($param->getAttributes()) {
foreach ($param->getAttributes() as $attr) {
echo " 屬性: " . $attr->getName() . "\n";
}
}
echo "\n";
}
<?php
class UserService {
public function create(string $name, int $age = 18): User {}
protected function notify(string $event, array $payload = []): void {}
}
$refMethod = new ReflectionMethod(UserService::class, 'create');
echo "create() 必填參數: " . $refMethod->getNumberOfRequiredParameters() . "\n"; // 1
| 場景 | Reflection 關鍵點 |
|---|---|
| 路由自動綁定參數 | 解析 Controller Method 參數名,從 Request 取值自動注入 |
| API 文檔自動生成 | 掃描 Controller,輸出 OpenAPI/Swagger 參數定義 |
| 依賴注入容器 | 構造函數參數類型提示 → 容器自動解析注入 |
| 參數驗證中介軟體 | 根據類型提示/屬性自動驗證 Request 資料 |
| 動態代理/裝飾器 | 檢查被代理方法簽名,轉發調用 |
| 測試數據生成 | 根據參數類型生成 Mock 數據 |
Reflection 涉及內部結構遍歷,比直接調用慢 10-100 倍。**生產環境必須快取**:
<?php
class ReflectionCache {
private static array $cache = [];
public static function getParameters(string $class, string $method): array {
$key = $class . '::' . $method;
if (!isset(self::$cache[$key])) {
$ref = new ReflectionMethod($class, $method);
self::$cache[$key] = $ref->getParameters();
}
return self::$cache[$key];
}
// 生產環境建議用 APCu/Redis 做跨進程快取
}
PHP 5 時代無類型提示,常用 @param 註解:
<?php
/**
* 建立用戶
* @param string $name 用戶名
* @param int $age 年齡
* @param string[] $tags 標籤
* @return User
*/
function createUser($name, $age = 18, $tags = []) {}
解析庫:phpdocumentor/reflection-docblock,現代專案建議直接用原生類型提示 + Reflection,避免註解與代碼不同步。
func_num_args() 只能在**函數內部**獲取**實際傳入**參數數