Skip to content

注解语法

概述

PHP 注解(Attributes)使用 #[...] 语法声明,支持命名空间、参数传递、重复注解和目标限制。掌握注解的完整语法是正确声明和使用注解的基础。本章将系统讲解注解的各种语法形式和声明规则。

基本语法

注解使用 #[ClassName(params)] 格式声明,放置在目标声明之前的行。

基础概念

声明位置

注解必须放在目标声明之前,可以独占一行,也可以在同一行。注解可以使用多个 #[...] 块,也可以用逗号分隔写在同一个块中。

命名空间

注解类可以(且应该)使用命名空间。如果注解类在当前命名空间中,可以省略命名空间前缀。

参数

注解的参数通过注解类的构造函数传递,支持命名参数和位置参数。

语法与代码

基本声明

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute]
class MyAnnotation
{
    public function __construct(public readonly string $value = '') {}
}

// 独占一行的注解
#[MyAnnotation]
function myFunction(): void {}

// 带参数的注解
#[MyAnnotation(value: 'hello')]
function anotherFunction(): void {}

多个注解的声明方式

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute]
class Route { public function __construct(public string $path = '') {} }
#[Attribute]
class Middleware { public function __construct(public string $name = '') {} }

// 方式一:多个 #[...] 块
#[Route(path: '/api/users')]
#[Middleware(name: 'auth')]
function getUsers(): array { return []; }

// 方式二:单个块中逗号分隔
#[Route(path: '/api/posts'), Middleware(name: 'cache')]
function getPosts(): array { return []; }

// 方式三:混合(PHP 8.0+ 支持嵌套)
#[Route(path: '/api'), Middleware(name: 'rate-limit')]
function apiEndpoint(): void {}

命名空间与 use 导入

php
<?php
declare(strict_types=1);

namespace App\Http\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
class Get {}

#[Attribute(Attribute::TARGET_METHOD)]
class Post {}

// 使用时
namespace App\Http\Controllers;

use App\Http\Attributes\Get;
use App\Http\Attributes\Post;

class UserController
{
    #[Get]
    public function index(): array { return []; }

    #[Post]
    public function store(): array { return []; }
}

注解参数语法

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute(Attribute::TARGET_CLASS)]
class Entity
{
    public function __construct(
        public readonly string $table,
        public readonly string $repository = '',
        public readonly bool $readonly = false
    ) {}
}

// 位置参数
#[Entity('users')]
class User {}

// 命名参数(PHP 8.0+)
#[Entity(table: 'products', readonly: true)]
class Product {}

// 混合参数
#[Entity('orders', repository: 'OrderRepository')]
class Order {}

注解中不使用命名参数的写法

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute]
class Config
{
    public function __construct(
        public readonly string $key,
        public readonly mixed $default = null
    ) {}
}

// 仅传递第一个参数
#[Config('app.name')]
class App {}

// 传递所有参数
#[Config('app.debug', false)]
class DebugConfig {}

重复注解

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_METHOD)]
class Role
{
    public function __construct(public readonly string $name) {}
}

// 同一方法上使用多次相同注解
class AdminController
{
    #[Role(name: 'admin')]
    #[Role(name: 'super-admin')]
    public function dashboard(): string
    {
        return 'Admin Dashboard';
    }
}

IS_REPEATABLE

如果不声明 Attribute::IS_REPEATABLE,同一目标上使用多次相同注解会引发错误。

目标限制

php
<?php
declare(strict_types=1);

use Attribute;

// 仅可用于类
#[Attribute(Attribute::TARGET_CLASS)]
class Entity { public function __construct(public string $table) {} }

// 仅可用于方法
#[Attribute(Attribute::TARGET_METHOD)]
class Route { public function __construct(public string $path) {} }

// 仅可用于属性
#[Attribute(Attribute::TARGET_PROPERTY)]
class Column { public function __construct(public string $type) {} }

// 仅可用于函数参数
#[Attribute(Attribute::TARGET_PARAMETER)]
class Validate { public function __construct(public string $rule) {} }

// 多个目标(位或组合)
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Cacheable {}

枚举 case 上的注解(PHP 8.1+)

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute(Attribute::TARGET_ENUM_CASE)]
class Description
{
    public function __construct(public readonly string $text) {}
}

enum Status: int
{
    #[Description(text: '活跃状态')]
    case Active = 1;

    #[Description(text: '禁用状态')]
    case Inactive = 2;

    #[Description(text: '待审核状态')]
    case Pending = 3;
}

函数参数上的注解

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute(Attribute::TARGET_PARAMETER)]
class MaxLength
{
    public function __construct(public readonly int $length) {}
}

#[Attribute(Attribute::TARGET_PARAMETER)]
class NotBlank {}

function validateInput(
    #[NotBlank]
    #[MaxLength(length: 255)]
    string $username,

    #[NotBlank]
    #[MaxLength(length: 100)]
    string $email
): void {
    // 验证逻辑...
}

详细说明

注解目标常量

常量说明
Attribute::TARGET_CLASS1类、接口、trait、枚举
Attribute::TARGET_FUNCTION2函数
Attribute::TARGET_METHOD4方法
Attribute::TARGET_PROPERTY8属性
Attribute::TARGET_CLASS_CONSTANT16类常量
Attribute::TARGET_PARAMETER32函数/方法参数
Attribute::TARGET_ALL63所有目标
Attribute::IS_REPEATABLE64允许在同一目标上重复使用

注解的嵌套

php
<?php
declare(strict_types=1);

use Attribute;

#[Attribute]
class Group
{
    public function __construct(public readonly string $name) {}
}

#[Attribute]
class Veto
{
    public function __construct(public readonly string $reason) {}
}

#[Group(name: 'admin'), Veto(reason: 'deprecated')]
class OldAdminController {}

实战示例

实战:构建完整的 API 注解系统

php
<?php
declare(strict_types=1);

namespace App\Annotations;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
class HttpGet
{
    public function __construct(public readonly string $path = '/') {}
}

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Middleware
{
    public function __construct(public readonly string $name) {}
}

#[Attribute(Attribute::TARGET_METHOD)]
class RequestBody
{
    public function __construct(public readonly string $class) {}
}

// 使用
namespace App\Controllers;

use App\Annotations\HttpGet;
use App\Annotations\Middleware;
use App\Annotations\RequestBody;

class ApiUserController
{
    #[HttpGet(path: '/api/v1/users')]
    #[Middleware(name: 'auth')]
    #[Middleware(name: 'throttle')]
    public function list(): array
    {
        return [];
    }

    #[HttpGet(path: '/api/v1/users/{id}')]
    #[Middleware(name: 'auth')]
    public function show(int $id): array
    {
        return ['id' => $id];
    }
}

注意事项

注解类必须是有效的 PHP 类

注解类必须是可以实例化的。抽象类、接口、trait 不能直接用作注解。

注解参数必须是常量表达式

注解的参数必须是 PHP 中有效的常量表达式(字面量、常量、枚举值等),不能是变量或函数调用。

php
<?php
declare(strict_types=1);

const CACHE_TTL = 3600;

#[Entity(table: 'users')]           // 正确:字面量
#[Cache(prefix: 'user_', ttl: CACHE_TTL)] // 正确:常量
// #[Cache(prefix: strtolower('X'))]       // 错误:不能使用函数调用

最佳实践

  1. 使用 readonly:注解类应该是 readonly 的(PHP 8.2+),确保不可变性。
  2. 指定目标:始终在 #[Attribute] 中明确指定目标限制。
  3. 使用构造函数验证:在构造函数中验证参数的合法性。
  4. 统一放在独立命名空间:如 App\Attributes
  5. 命名清晰:注解类名应清晰表达其用途。
php
<?php
declare(strict_types=1);

namespace App\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
readonly class HttpPost
{
    public function __construct(public readonly string $path = '/') {}
}

参考链接