Laravel 13 PHP Attributes 完全指南
摘要
Laravel 13 大幅扩展了 PHP 8 Attributes 的支持,新增 36 个属性,让配置更加声明式和直观。本文将全面解析 Laravel 13 中的 PHP Attributes 应用,包括:
- PHP Attributes 核心概念与语法
- Laravel 13 新增属性一览
- 控制器属性详解
- 路由属性应用
- 验证属性使用
- 自定义属性创建
本文适合希望采用声明式配置风格的 Laravel 开发者。
1. PHP Attributes 概述
1.1 什么是 PHP Attributes
PHP Attributes 是 PHP 8.0 引入的特性,允许在类、方法、属性等声明上添加结构化元数据。Laravel 13 充分利用这一特性,将传统配置方式转变为声明式风格。
1.2 传统方式 vs Attributes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Route::get('/users', [UserController::class, 'index']) ->middleware('auth') ->name('users.index');
class UserController extends Controller { #[Get('/users', name: 'users.index')] #[Middleware('auth')] public function index() { } }
|
1.3 核心优势
| 优势 | 描述 |
|---|
| 配置集中 | 配置与代码放在一起 |
| 可读性强 | 一目了然的声明式风格 |
| IDE 友好 | 更好的代码提示和导航 |
| 类型安全 | 编译时检查 |
| 减少样板代码 | 减少配置文件内容 |
2. Laravel 13 新增属性一览
2.1 控制器属性
| 属性 | 用途 |
|---|
#[Middleware] | 定义中间件 |
#[Authorize] | 定义授权策略 |
#[Route] | 定义路由 |
#[Get] | GET 路由快捷方式 |
#[Post] | POST 路由快捷方式 |
#[Put] | PUT 路由快捷方式 |
#[Delete] | DELETE 路由快捷方式 |
#[Patch] | PATCH 路由快捷方式 |
2.2 队列属性
| 属性 | 用途 |
|---|
#[Tries] | 最大尝试次数 |
#[Backoff] | 重试间隔 |
#[Timeout] | 超时时间 |
#[FailOnTimeout] | 超时失败 |
#[MaxExceptions] | 最大异常数 |
#[WithoutOverlapping] | 防止重叠 |
#[ShouldBeUnique] | 唯一任务 |
2.3 验证属性
| 属性 | 用途 |
|---|
#[Rule] | 验证规则 |
#[Required] | 必填验证 |
#[Email] | 邮箱验证 |
#[Url] | URL 验证 |
#[Date] | 日期验证 |
2.4 Eloquent 属性
| 属性 | 用途 |
|---|
#[ObservedBy] | 观察者 |
#[Scope] | 查询作用域 |
#[Accessor] | 访问器 |
#[Mutator] | 修改器 |
3. 控制器属性详解
3.1 中间件属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?php
namespace App\Http\Controllers;
use Illuminate\Routing\Attributes\Controllers\Middleware;
#[Middleware('auth')] class UserController extends Controller { #[Middleware('verified')] public function dashboard() { } #[Middleware(['auth', 'admin'])] public function adminPanel() { } #[Middleware('throttle:60,1')] public function api() { } }
|
3.2 中间件排除
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #[Middleware('auth')] class UserController extends Controller { public function index() { } #[Middleware(except: ['auth'])] public function public() { } }
|
3.3 授权属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?php
namespace App\Http\Controllers;
use App\Models\Post; use Illuminate\Routing\Attributes\Controllers\Authorize;
class PostController extends Controller { #[Authorize('create', Post::class)] public function create() { } #[Authorize('update', 'post')] public function update(Post $post) { } #[Authorize('delete', [Post::class, 'post'])] public function destroy(Post $post) { } }
|
4. 路由属性详解
4.1 基本路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <?php
namespace App\Http\Controllers;
use Illuminate\Routing\Attributes\Get; use Illuminate\Routing\Attributes\Post; use Illuminate\Routing\Attributes\Put; use Illuminate\Routing\Attributes\Delete;
class PostController extends Controller { #[Get('/posts')] public function index() { } #[Get('/posts/{post}')] public function show(Post $post) { } #[Post('/posts')] public function store() { } #[Put('/posts/{post}')] public function update(Post $post) { } #[Delete('/posts/{post}')] public function destroy(Post $post) { } }
|
4.2 路由参数
1 2 3 4 5 6 7 8 9 10 11
| #[Get('/users/{user}/posts/{post}')] public function showUserPost(User $user, Post $post) { }
#[Get('/posts/{post:slug}')] public function showBySlug(Post $post) { }
|
4.3 路由名称
1 2 3 4 5 6 7 8 9 10 11
| #[Get('/posts', name: 'posts.index')] public function index() { }
#[Get('/posts/{post}', name: 'posts.show')] public function show(Post $post) { }
|
4.4 路由组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
namespace App\Http\Controllers;
use Illuminate\Routing\Attributes\Middleware; use Illuminate\Routing\Attributes\Prefix; use Illuminate\Routing\Attributes\Get;
#[Prefix('api/v1')] #[Middleware(['auth:sanctum', 'throttle:api'])] class ApiPostController extends Controller { #[Get('/posts')] public function index() { } #[Get('/posts/{post}')] public function show(Post $post) { } }
|
4.5 资源路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php
namespace App\Http\Controllers;
use Illuminate\Routing\Attributes\Resource;
#[Resource('posts')] class PostController extends Controller { public function index() {} public function create() {} public function store() {} public function show($id) {} public function edit($id) {} public function update($id) {} public function destroy($id) {} }
|
5. 验证属性详解
5.1 表单请求验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Attributes\Rule; use Illuminate\Validation\Attributes\Required; use Illuminate\Validation\Attributes\Email; use Illuminate\Validation\Attributes\Password;
class StoreUserRequest extends FormRequest { public function rules(): array { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'email', 'unique:users'], 'password' => ['required', Password::defaults()], ]; } }
|
5.2 模型属性验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Validation\Attributes\Required; use Illuminate\Validation\Attributes\Email; use Illuminate\Validation\Attributes\Rule;
class User extends Model { #[Required] #[Rule('string', 'max:255')] protected string $name; #[Required] #[Email] #[Rule('unique:users')] protected string $email; }
|
6. 队列属性详解
6.1 任务配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
namespace App\Jobs;
use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\Attributes\Tries; use Illuminate\Queue\Attributes\Backoff; use Illuminate\Queue\Attributes\Timeout; use Illuminate\Queue\Attributes\FailOnTimeout;
#[Tries(3)] #[Backoff([10, 30, 60])] #[Timeout(120)] #[FailOnTimeout] class ProcessPodcast implements ShouldQueue { use Queueable; public function handle() { } }
|
6.2 唯一任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?php
namespace App\Jobs;
use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\Attributes\ShouldBeUnique; use Illuminate\Queue\Attributes\WithoutOverlapping;
#[ShouldBeUnique(3600)] class SendWelcomeEmail implements ShouldQueue { use Queueable; public function uniqueId(): string { return $this->user->id; } }
#[WithoutOverlapping(10)] class GenerateReport implements ShouldQueue { use Queueable; }
|
6.3 队列连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
namespace App\Jobs;
use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\Attributes\OnConnection; use Illuminate\Queue\Attributes\OnQueue;
#[OnConnection('redis')] #[OnQueue('podcasts')] class ProcessPodcast implements ShouldQueue { use Queueable; }
|
7. Eloquent 属性详解
7.1 观察者
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Attributes\ObservedBy; use App\Observers\UserObserver;
#[ObservedBy(UserObserver::class)] class User extends Model { }
|
7.2 查询作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Attributes\Scope;
class User extends Model { #[Scope] public function active($query) { return $query->where('active', true); } #[Scope] public function ofType($query, string $type) { return $query->where('type', $type); } }
User::active()->ofType('admin')->get();
|
7.3 访问器和修改器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Attributes\Accessor; use Illuminate\Database\Eloquent\Attributes\Mutator;
class User extends Model { #[Accessor] public function fullName(): Attribute { return Attribute::make( get: fn($value, $attributes) => $attributes['first_name'] . ' ' . $attributes['last_name'], ); } #[Mutator] public function password(): Attribute { return Attribute::make( set: fn($value) => bcrypt($value), ); } }
|
8. 自定义属性
8.1 创建自定义属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
namespace App\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] class LogActivity { public function __construct( public string $action, public string $description = '', ) {} }
|
8.2 使用自定义属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
namespace App\Http\Controllers;
use App\Attributes\LogActivity;
class PostController extends Controller { #[LogActivity('post.created', 'User created a new post')] public function store() { } #[LogActivity('post.deleted', 'User deleted a post')] public function destroy($id) { } }
|
8.3 处理自定义属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php
namespace App\Services;
use Illuminate\Support\Facades\Log; use ReflectionClass;
class ActivityLogService { public function log(object $controller, string $method): void { $reflection = new ReflectionClass($controller); $methodReflection = $reflection->getMethod($method); $attributes = $methodReflection->getAttributes(LogActivity::class); foreach ($attributes as $attribute) { $log = $attribute->newInstance(); Log::info("Activity: {$log->action}", [ 'description' => $log->description, 'user_id' => auth()->id(), ]); } } }
|
9. 最佳实践
9.1 属性组织
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
namespace App\Http\Controllers;
use Illuminate\Routing\Attributes\Get; use Illuminate\Routing\Attributes\Middleware; use Illuminate\Routing\Attributes\Authorize; use Illuminate\Routing\Attributes\Prefix;
#[Prefix('api/v1')] #[Middleware(['auth:sanctum', 'throttle:api'])] class PostController extends Controller { #[Get('/posts')] #[Authorize('viewAny', Post::class)] public function index() { } }
|
9.2 避免过度使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #[Get('/posts')] #[Middleware('auth')] #[Middleware('verified')] #[Middleware('admin')] #[Authorize('viewAny')] #[Throttle(60)] #[Cache(3600)] public function index() {}
#[Get('/posts')] #[Middleware(['auth', 'verified', 'admin'])] #[Authorize('viewAny')] public function index() {}
|
9.3 文档注释
1 2 3 4 5 6 7 8 9 10 11
|
#[Get('/posts', name: 'posts.index')] #[Authorize('viewAny', Post::class)] public function index() { }
|
10. 总结
Laravel 13 的 PHP Attributes 支持为开发者提供了声明式配置的强大能力:
- 配置集中:配置与代码放在一起,更易维护
- 类型安全:编译时检查,减少错误
- IDE 友好:更好的代码提示和导航
- 可扩展:支持自定义属性
通过本指南,您已经掌握了 Laravel 13 PHP Attributes 的核心用法,可以开始采用声明式风格编写代码了。
参考资料