PHP反射与注解详解
反射(Reflection)
什么是反射
反射是PHP在运行时获取类、方法、属性、参数等结构信息的机制。

核心反射类
<?php
// 示例类
class User {
private int $id;
public string $name;
protected string $email;
public function __construct(string $name, string $email) {
$this->name = $name;
$this->email = $email;
}
public function getName(): string {
return $this->name;
}
private function validateEmail(): bool {
return filter_var($this->email, FILTER_VALIDATE_EMAIL) !== false;
}
}
// 获取反射对象
$reflectionClass = new ReflectionClass(User::class);
// 获取类信息
echo "类名: " . $reflectionClass->getName() . "\n";
echo "父类: " . ($reflectionClass->getParentClass()?->getName() ?? '无') . "\n";
echo "是否抽象: " . ($reflectionClass->isAbstract() ? '是' : '否') . "\n";
// 获取属性
$properties = $reflectionClass->getProperties();
foreach ($properties as $property) {
echo "属性: {$property->getName()} ({$property->getModifiers()})\n";
}
// 获取方法
$methods = $reflectionClass->getMethods();
foreach ($methods as $method) {
echo "方法: {$method->getName()} (访问修饰符: {$method->getModifiers()})\n";
}
反射的实际应用
<?php
// 依赖注入容器(简化版)
class Container {
private array $instances = [];
public function get(string $className) {
if (!isset($this->instances[$className])) {
$this->instances[$className] = $this->resolve($className);
}
return $this->instances[$className];
}
private function resolve(string $className) {
$reflectionClass = new ReflectionClass($className);
// 检查是否可实例化
if (!$reflectionClass->isInstantiable()) {
throw new Exception("Class {$className} cannot be instantiated");
}
// 获取构造函数
$constructor = $reflectionClass->getConstructor();
if ($constructor === null) {
return new $className();
}
// 解析构造函数参数
$parameters = $constructor->getParameters();
$dependencies = [];
foreach ($parameters as $parameter) {
$type = $parameter->getType();
if ($type === null || $type->isBuiltin()) {
if ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
} else {
throw new Exception("Cannot resolve parameter: {$parameter->getName()}");
}
} else {
$dependencies[] = $this->get($type->getName());
}
}
return $reflectionClass->newInstanceArgs($dependencies);
}
}
// 使用示例
class Database {
public function query(string $sql) {
return "Executing: {$sql}";
}
}
class UserRepository {
private Database $database;
public function __construct(Database $database) {
$this->database = $database;
}
public function findAll() {
return $this->database->query("SELECT * FROM users");
}
}
$container = new Container();
$userRepo = $container->get(UserRepository::class);
echo $userRepo->findAll();
注解(Attributes)- PHP 8+
定义注解
<?php
// 定义注解类
#[Attribute]
class Route {
public function __construct(
public string $path,
public string $method = 'GET'
) {}
}
#[Attribute]
class Middleware {
public function __construct(
public string $name,
public array $options = []
) {}
}
#[Attribute]
class Validation {
public function __construct(
public array $rules = []
) {}
}
使用注解
<?php
// 使用注解
#[Route('/users', 'GET')]
#[Middleware('auth')]
#[Middleware('log')]
class UserController {
#[Route('/users/{id}', 'GET')]
#[Validation(['id' => 'required|numeric'])]
public function show(int $id): array {
return ['user' => ['id' => $id, 'name' => 'John']];
}
#[Route('/users', 'POST')]
#[Validation(['name' => 'required|string', 'email' => 'required|email'])]
public function store(array $data): array {
return ['status' => 'created'];
}
}
读取注解
<?php
// 路由处理器
class RouteHandler {
private array $routes = [];
public function registerControllers(string ...$controllers): void {
foreach ($controllers as $controller) {
$this->registerController($controller);
}
}
private function registerController(string $controllerClass): void {
$reflectionClass = new ReflectionClass($controllerClass);
// 读取类注解
$classAttributes = $reflectionClass->getAttributes();
$classMiddleware = [];
foreach ($classAttributes as $attribute) {
if ($attribute->getName() === Middleware::class) {
$middleware = $attribute->newInstance();
$classMiddleware[] = $middleware->name;
}
}
// 读取方法注解
foreach ($reflectionClass->getMethods() as $method) {
$methodAttributes = $method->getAttributes(Route::class);
foreach ($methodAttributes as $attribute) {
$route = $attribute->newInstance();
$this->routes[$route->method][$route->path] = [
'controller' => $controllerClass,
'method' => $method->getName(),
'middleware' => $classMiddleware,
'validation' => $this->getValidationRules($method)
];
}
}
}
private function getValidationRules(ReflectionMethod $method): array {
$attributes = $method->getAttributes(Validation::class);
if (empty($attributes)) {
return [];
}
$validation = $attributes[0]->newInstance();
return $validation->rules;
}
public function dispatch(string $method, string $path): void {
$path = rtrim($path, '/');
foreach ($this->routes[$method] ?? [] as $routePath => $routeInfo) {
// 简单的路径匹配(实际项目应使用正则)
if ($this->matchPath($routePath, $path)) {
$this->executeRoute($routeInfo, $path);
return;
}
}
throw new Exception("Route not found: {$method} {$path}");
}
private function matchPath(string $pattern, string $path): bool {
// 简化的路径匹配
$pattern = preg_replace('/\{([a-zA-Z_]+)\}/', '([^/]+)', $pattern);
return preg_match("#^{$pattern}$#", $path) === 1;
}
private function executeRoute(array $routeInfo, string $path): void {
$controllerClass = $routeInfo['controller'];
$methodName = $routeInfo['method'];
// 执行中间件
foreach ($routeInfo['middleware'] as $middleware) {
echo "执行中间件: {$middleware}\n";
}
// 执行控制器方法
$controller = new $controllerClass();
$controller->$methodName(1);
}
}
// 使用示例
$handler = new RouteHandler();
$handler->registerControllers(UserController::class);
try {
$handler->dispatch('GET', '/users/123');
echo "\n\n";
$handler->dispatch('POST', '/users');
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
综合应用:ORM框架示例
<?php
// 定义ORM相关注解
#[Attribute]
class Table {
public function __construct(
public string $name
) {}
}
#[Attribute]
class Column {
public function __construct(
public string $name,
public string $type = 'string',
public bool $nullable = false
) {}
}
#[Attribute]
class Id {
public function __construct(
public bool $autoIncrement = true
) {}
}
#[Attribute]
class OneToMany {
public function __construct(
public string $targetEntity,
public string $mappedBy
) {}
}
// 实体类
#[Table('users')]
class User {
#[Id]
#[Column('id', 'integer')]
private int $id;
#[Column('username', 'string')]
private string $username;
#[Column('email', 'string')]
private string $email;
#[Column('created_at', 'datetime')]
private ?DateTime $createdAt = null;
#[OneToMany(Post::class, 'user_id')]
private array $posts = [];
}
// ORM映射器
class EntityMapper {
private array $entityMap = [];
public function registerEntity(string $entityClass): void {
$reflectionClass = new ReflectionClass($entityClass);
// 获取表名
$tableAttributes = $reflectionClass->getAttributes(Table::class);
if (empty($tableAttributes)) {
throw new Exception("Entity {$entityClass} must have Table attribute");
}
$table = $tableAttributes[0]->newInstance();
$tableName = $table->name;
// 解析列映射
$columns = [];
$relations = [];
foreach ($reflectionClass->getProperties() as $property) {
$this->parseProperty($property, $columns, $relations);
}
$this->entityMap[$entityClass] = [
'table' => $tableName,
'columns' => $columns,
'relations' => $relations
];
}
private function parseProperty(ReflectionProperty $property, array &$columns, array &$relations): void {
$attributes = $property->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
if ($instance instanceof Column) {
$columns[$property->getName()] = [
'name' => $instance->name,
'type' => $instance->type,
'nullable' => $instance->nullable
];
} elseif ($instance instanceof OneToMany) {
$relations[$property->getName()] = [
'type' => 'oneToMany',
'targetEntity' => $instance->targetEntity,
'mappedBy' => $instance->mappedBy
];
}
}
}
public function getTableName(string $entityClass): string {
return $this->entityMap[$entityClass]['table'] ?? '';
}
public function getColumns(string $entityClass): array {
return $this->entityMap[$entityClass]['columns'] ?? [];
}
}
// 使用示例
$mapper = new EntityMapper();
$mapper->registerEntity(User::class);
echo "Table: " . $mapper->getTableName(User::class) . "\n";
echo "Columns:\n";
print_r($mapper->getColumns(User::class));
最佳实践
性能优化
// 缓存反射结果
class ReflectionCache {
private static array $cache = [];
public static function getClass(string $className): ReflectionClass {
if (!isset(self::$cache[$className])) {
self::$cache[$className] = new ReflectionClass($className);
}
return self::$cache[$className];
}
public static function getAttributes(string $className, string $attributeName): array {
$reflectionClass = self::getClass($className);
return $reflectionClass->getAttributes($attributeName);
}
}
特性比较
| 特性 | 旧版PHP注解 | PHP 8+ Attributes |
|---|---|---|
| 语法 | 通过文档注释解析 | 原生支持,明确语法 |
| 性能 | 需要解析字符串 | 直接读取,性能更好 |
| 类型安全 | 无类型检查 | 有明确的类型定义 |
| IDE支持 | 有限 | 原生支持,代码补全 |
注意事项
- 性能影响:反射操作相对较慢,建议缓存结果
- 版本要求:Attributes需要PHP 8.0+版本
- 测试覆盖:使用反射的代码需要充分的单元测试
- 可维护性:避免过度使用,保持代码简洁性
- 错误处理:确保反射操作有适当的错误处理机制
反射和注解是现代PHP框架的基础,合理使用可以构建灵活、可扩展的应用架构。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播