PHP Reflection API 提供運行時檢測類、接口、方法、屬性、參數的能力,是框架級開發(依賴注入、插件系統、自動配置)的基石。本文展示兩個實戰場景:基於配置動態加載並驗證第三方模塊、提取類源碼,並附帶核心 Reflection 類速查表。
Module 子類、構造參數匹配、必要方法存在abstract class Module {
public function baseFunc() { echo "baseFunc\n"; }
abstract public function execute();
}
class ModuleRunner {
private $config = [
'PersonModule' => ['person' => 'bob'],
'FtpModule' => ['host' => 'example.com', 'user' => 'anon'],
];
private $modules = [];
public function init() {
$parent = new ReflectionClass(Module::class);
foreach ($this->config as $className => $params) {
// 1. 類存在性 & 繼承關係驗證
if (!class_exists($className)) {
throw new Exception("Class $className not found");
}
$moduleClass = new ReflectionClass($className);
if (!$moduleClass->isSubclassOf($parent)) {
throw new Exception("$className is not a Module subclass");
}
// 2. 實例化(支援帶參構造函數)
$module = $moduleClass->newInstanceArgs(
$this->resolveConstructorArgs($moduleClass, $params)
);
// 3. setter 注入配置(約定:setXxx 對應配鍵 xxx)
foreach ($moduleClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
$this->injectSetter($module, $method, $params);
}
$this->modules[] = $module;
}
}
private function resolveConstructorArgs(ReflectionClass $class, array $params) {
$ctor = $class->getConstructor();
if (!$ctor) return [];
$args = [];
foreach ($ctor->getParameters() as $param) {
$name = $param->getName();
if (isset($params[$name])) {
$type = $param->getType();
if ($type && !$type->isBuiltin()) {
// 類型提示為類,自動實例化
$args[] = new $type($params[$name]);
} else {
$args[] = $params[$name];
}
} elseif ($param->isOptional()) {
$args[] = $param->getDefaultValue();
} else {
throw new Exception("Missing required constructor param: $name");
}
}
return $args;
}
private function injectSetter($module, ReflectionMethod $method, array $params) {
$name = $method->getName();
if (strncmp($name, 'set', 3) !== 0) return; // 僅處理 setXxx
$prop = lcfirst(substr($name, 3));
if (!isset($params[$prop])) return;
$method->invoke($module, $params[$prop]);
}
public function getModules() { return $this->modules; }
}
// 第三方類示例
class Person { public $name; public function __construct($n) { $this->name = $n; } }
class PersonModule extends Module {
private $person;
public function setPerson(Person $p) { $this->person = $p; }
public function execute() { echo "I am {$this->person->name}\n"; }
}
class FtpModule extends Module {
private $host, $user;
public function setHost($h) { $this->host = $h; }
public function setUser($u) { $this->user = $u; }
public function execute() { echo "{$this->user} @ {$this->host}\n"; }
}
// 運行
$runner = new ModuleRunner();
$runner->init();
foreach ($runner->getModules() as $m) { $m->execute(); }
I am bob anon @ example.com
function getSource(ReflectionClass $ref) {
$file = $ref->getFileName(); // 文件路徑
$lines = file($file); // 全文按行讀入數組
$start = $ref->getStartLine(); // 類定義起始行(1-based)
$end = $ref->getEndLine(); // 類定義結束行
// array_slice 參數:offset 0-based,length
$source = implode('', array_slice($lines, $start - 1, $end - $start + 1));
return $source;
}
class Demo {
public $x = 1;
private function foo() { return 'bar'; }
}
$ref = new ReflectionClass(Demo::class);
echo getSource($ref);
| 方法 | 用途 |
|---|---|
getFileName() | 定義類的文件路徑 |
getStartLine() / getEndLine() | 類定義起止行號 |
getMethods() | 所有方法 ReflectionMethod 數組 |
getProperties() | 所有屬性 ReflectionProperty 數組 |
getConstructor() | 構造函數 ReflectionMethod |
isSubclassOf() | 繼承關係檢查 |
implementsInterface() | 接口實現檢查 |
newInstanceArgs() | 帶參數實例化 |
$method = new ReflectionClass('SomeClass')->getMethod('doWork');
$method->getParameters(); // 參數列表
$method->getReturnType(); // 返回類型 (PHP 7+)
$method->isPublic/Protected/Private();
$method->isStatic/Abstract/Final();
$param = $method->getParameters()[0];
$param->getName(); // 參數名
$param->getType(); // 類型提示 ReflectionNamedType
$param->isOptional(); // 是否有默認值
$param->getDefaultValue(); // 默認值
$param->allowsNull(); // 是否可為 null
Reflection 讓 PHP 擁有「自我認知」能力,支撐起現代框架的 IoC 容器、路由掃描、實體映射、API 文檔自動生成等核心功能。掌握 ReflectionClass/Method/Parameter 三大核心類,並建立**緩存機制**,即可在業務項目中安全引入動態加載與結構驗證能力。