Laravel 13 全面拥抱了PHP 属性。过去多年来你一直在模型中定义的属性,例如$fillable`name`、$guarded`name` 和`name`,现在可以声明为类级属性: `name`、`name` 和`name`。同样的情况也适用于作业配置、控制台命令签名、中间件等等。$hidden#[Fillable]#[Guarded]#[Hidden]
在本文中,我将带您了解Laravel 13 中所有可用的 PHP 属性——包括新增属性和之前已存在的属性——并为每个属性提供实际的代码示例。
重要提示:这些属性是可选的,在所有这些情况下您都可以使用旧语法。这些属性并非破坏性变更,只是提供了新的替代方案。
Laravel 13 新增功能
Eloquent 模型属性
这些属性可以取代之前我们一直编写的熟悉的模型属性。
1. #[Fillable]— 定义批量赋值字段
旧:
class Post extends Model{
protected $fillable = ['title', 'body', 'status'];
}
新:
use Illuminate\Database\Eloquent\Attributes\Fillable;
#[Fillable(['title', 'body', 'status'])]
class Post extends Model{}
2. #[Guarded]— 定义受保护字段
旧:
class User extends Model{
protected $guarded = ['id', 'is_admin'];
}
新:
use Illuminate\Database\Eloquent\Attributes\Guarded;
#[Guarded(['id', 'is_admin'])]
class User extends Model{}
3. #[Unguarded]— 禁用批量分配保护
标记属性——无需参数。
旧:
class Setting extends Model{
protected $guarded = [];
}
新:
use Illuminate\Database\Eloquent\Attributes\Unguarded;
#[Unguarded]
class Setting extends Model{}
4. #[Hidden]— 隐藏序列化字段
旧:
class User extends Model{
protected $hidden = ['password', 'remember_token'];
}
新:
use Illuminate\Database\Eloquent\Attributes\Hidden;
#[Hidden(['password', 'remember_token'])]
class User extends Model{}
5. #[Visible]— 明确定义可见字段
旧:
class User extends Model{
protected $visible = ['id', 'name', 'email'];
}
新:
use Illuminate\Database\Eloquent\Attributes\Visible;
#[Visible(['id', 'name', 'email'])]
class User extends Model{}
6. #[Appends]— 自动向 JSON 追加访问器
旧:
class User extends Model{
protected $appends = ['full_name', 'is_active'];
public function getFullNameAttribute(): string {
return $this->first_name.' '.$this->last_name;
}
}
新:
use Illuminate\Database\Eloquent\Attributes\Appends;
#[Appends(['full_name', 'is_active'])]
class User extends Model{
public function getFullNameAttribute(): string {
return $this->first_name.' '.$this->last_name;
}
}
7. #[Table]— 设置表名和键配置
这个功能很强大——它可以一次性替换多个属性:$table$primaryKey$keyType$incrementing$timestamps$dateFormat…
旧:
class Post extends Model{
protected $table = 'blog_posts';
protected $primaryKey = 'post_id';
}
新:
use Illuminate\Database\Eloquent\Attributes\Table;
#[Table('blog_posts', key: 'post_id')]
class Post extends Model{}
包含所有选项:
旧:
class ExternalOrder extends Model{
protected $table = 'external_orders';
protected $primaryKey = 'uuid';
protected $keyType = 'string';
public $incrementing = false;
public $timestamps = false;
}
后:
#[Table(name: 'external_orders', key: 'uuid', keyType: 'string', incrementing: false, timestamps: false,)]
class ExternalOrder extends Model{}
8. #[Connection]— 设置模型数据库连接
旧:
class PageView extends Model{
protected $connection = 'analytics';
}
新:
use Illuminate\Database\Eloquent\Attributes\Connection;
#[Connection('analytics')]
class PageView extends Model{}
9. #[Touches]— touch时间戳
旧:
class Comment extends Model{
protected $touches = ['post'];
public function post(): BelongsTo {
return $this->belongsTo(Post::class);
}
}
新:
use Illuminate\Database\Eloquent\Attributes\Touches;
#[Touches(['post'])]
class Comment extends Model{
public function post(): BelongsTo {
return $this->belongsTo(Post::class);
}
}
队列/作业属性
使用声明式方法配置作业,而不是设置属性。
10. #[Tries]— 设置最大尝试次数
前:
class ProcessPayment implements ShouldQueue{ public $tries = 3;}
后:
use Illuminate\Queue\Attributes\Tries;#[Tries(3)]class ProcessPayment implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;}
11. #[Timeout]— 设置作业超时
前:
class GenerateReport implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public $timeout = 120;}
后:
use Illuminate\Queue\Attributes\Timeout;#[Timeout(120)]class GenerateReport implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;}
12. #[Backoff]— 设置重试退避
前:
class SyncInventory implements ShouldQueue{ public $backoff = 30; // Or for exponential backoff: // public $backoff = [10, 30, 60];}
后:
use Illuminate\Queue\Attributes\Backoff;// Fixed backoff#[Backoff(30)]class SyncInventory implements ShouldQueue{}// Exponential backoff#[Backoff([10, 30, 60])]class SyncInventory implements ShouldQueue{}
13. #[MaxExceptions]— 失败前的最大异常次数
前:
class ImportCsvRows implements ShouldQueue{ public $maxExceptions = 3;}
后:
use Illuminate\Queue\Attributes\MaxExceptions;#[MaxExceptions(3)]class ImportCsvRows implements ShouldQueue{}
14. #[Queue]— 设置队列名称
前:
class SendWelcomeEmail implements ShouldQueue{ public $queue = 'high';}
后:
use Illuminate\Queue\Attributes\Queue;#[Queue('high')]class SendWelcomeEmail implements ShouldQueue{}
15. #[Connection]— 设置队列连接
前:
class ProcessWebhook implements ShouldQueue{ public $connection = 'redis';}
后:
use Illuminate\Queue\Attributes\Connection;#[Connection('redis')]class ProcessWebhook implements ShouldQueue{}
16. #[UniqueFor]— 唯一作业锁定持续时间
前:
class RebuildSearchIndex implements ShouldQueue, ShouldBeUnique{ public $uniqueFor = 3600;}
后:
use Illuminate\Queue\Attributes\UniqueFor;use Illuminate\Contracts\Queue\ShouldBeUnique;#[UniqueFor(3600)]class RebuildSearchIndex implements ShouldQueue, ShouldBeUnique{}
17. #[FailOnTimeout]— 超时时失败而不是重试
前:
class CallExternalApi implements ShouldQueue{ public $failOnTimeout = true;}
后:
use Illuminate\Queue\Attributes\FailOnTimeout;#[FailOnTimeout]class CallExternalApi implements ShouldQueue{}
您可以组合多个职位属性:
use Illuminate\Queue\Attributes\{Connection, Queue, Tries, Timeout, Backoff};#[Connection('redis')]#[Queue('high')]#[Tries(3)]#[Timeout(60)]#[Backoff([5, 15, 30])]class ProcessPayment implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;}
控制台命令属性
定义 Artisan 命令时,请勿包含$signature, $description, 和$help属性。
18. #[Signature]— 定义命令签名
前:
class PruneUsers extends Command{ protected $signature = 'users:prune {--days=30 : Days of inactivity}'; protected $description = 'Prune inactive user accounts';}
后:
use Illuminate\Console\Attributes\Signature;use Illuminate\Console\Attributes\Description;#[Signature('users:prune {--days=30 : Days of inactivity}')]#[Description('Prune inactive user accounts')]class PruneUsers extends Command{ public function handle(): void { $days = $this->option('days'); // ... }}
该Signature属性也接受别名:
#[Signature('cache:warm', aliases: ['warm-cache'])]class WarmCache extends Command{}
19. #[Description]— 设置命令说明
前:
class SendMarketingEmails extends Command{ protected $description = 'Send scheduled marketing emails';}
后:
use Illuminate\Console\Attributes\Description;#[Description('Send scheduled marketing emails')]class SendMarketingEmails extends Command{}
20. #[Help]— 设置帮助文本
前:
class ProcessOrders extends Command{ protected $help = 'This command processes all pending orders and sends confirmation emails. Run during off-peak hours.';}
后:
use Illuminate\Console\Attributes\Help;#[Help('This command processes all pending orders and sends confirmation emails. Run during off-peak hours.')]class ProcessOrders extends Command{}
21. #[Hidden]— 从列表中隐藏命令
前:
class DebugInternals extends Command{ protected $hidden = true;}
后:
use Illuminate\Console\Attributes\Hidden;#[Hidden]class DebugInternals extends Command{}
22. #[Usage]— 添加使用示例(可重复使用)
前:
class PruneUsers extends Command{ protected $help = <<<'HELP' Usage examples: users:prune --days=60 users:prune --days=30 --dry-run HELP;}
后:
use Illuminate\Console\Attributes\Usage;#[Usage('users:prune --days=60')]#[Usage('users:prune --days=30 --dry-run')]class PruneUsers extends Command{}
路由和控制器属性
23. #[Middleware]— 将中间件附加到控制器
在类级别、方法级别或两者兼而有之的情况下应用中间件。此操作可重复执行。
前:
class DashboardController extends Controller{ public function __construct() { $this->middleware(['auth', 'verified']); } public function index() { return view('dashboard'); }}
后:
use Illuminate\Routing\Attributes\Controllers\Middleware;#[Middleware('auth')]#[Middleware('verified')]class DashboardController extends Controller{ public function index() { return view('dashboard'); }}
only使用`and`将中间件限制为特定方法except:
#[Middleware('auth')]#[Middleware('admin', only: ['destroy'])]#[Middleware('throttle:60,1', except: ['index', 'show'])]class PostController extends Controller{ // ...}
将中间件应用于各个方法:
class ReportController extends Controller{ #[Middleware('cache.headers:public;max_age=3600')] public function show(Report $report) { return view('reports.show', compact('report')); }}
24. #[Authorize]— 控制器上的门禁授权
前:
class PostController extends Controller{ public function __construct() { $this->authorizeResource(Post::class, 'post'); } public function edit(Post $post) { return view('posts.edit', compact('post')); }}
后:
use Illuminate\Routing\Attributes\Controllers\Authorize;#[Authorize('viewAny', Post::class)]class PostController extends Controller{ #[Authorize('update', Post::class)] public function edit(Post $post) { return view('posts.edit', compact('post')); }}
仅限特定方法:
#[Authorize('manage-users', only: ['edit', 'update', 'destroy'])]class UserController extends Controller{}
表单请求属性
25. #[ErrorBag]— 设置命名错误包
前:
class CreatePostRequest extends FormRequest{ protected $errorBag = 'createPost';}
后:
use Illuminate\Foundation\Http\Attributes\ErrorBag;#[ErrorBag('createPost')]class CreatePostRequest extends FormRequest{ public function rules(): array { return ['title' => 'required|max:255']; }}
26. #[RedirectTo]— 验证失败时的重定向 URL
前:
class StorePostRequest extends FormRequest{ protected $redirect = '/posts/create'; public function rules(): array { return ['title' => 'required']; }}
后:
use Illuminate\Foundation\Http\Attributes\RedirectTo;#[RedirectTo('/posts/create')]class StorePostRequest extends FormRequest{ public function rules(): array { return ['title' => 'required']; }}
27. #[RedirectToRoute]— 失败时重定向到指定路由
前:
class StorePostRequest extends FormRequest{ protected $redirectRoute = 'posts.create'; public function rules(): array { return ['title' => 'required']; }}
后:
use Illuminate\Foundation\Http\Attributes\RedirectToRoute;#[RedirectToRoute('posts.create')]class StorePostRequest extends FormRequest{ public function rules(): array { return ['title' => 'required']; }}
28. #[StopOnFirstFailure]— 遇到第一个错误时停止验证
前:
class ImportRequest extends FormRequest{ protected $stopOnFirstFailure = true; public function rules(): array { return [ 'file' => 'required|file|mimes:csv', 'mapping' => 'required|array', ]; }}
后:
use Illuminate\Foundation\Http\Attributes\StopOnFirstFailure;#[StopOnFirstFailure]class ImportRequest extends FormRequest{ public function rules(): array { return [ 'file' => 'required|file|mimes:csv', 'mapping' => 'required|array', ]; }}
HTTP资源属性
29. #[Collects]— 定义资源集合类型
前:
class PostCollection extends ResourceCollection{ public $collects = PostResource::class;}
后:
use Illuminate\Http\Resources\Attributes\Collects;#[Collects(PostResource::class)]class PostCollection extends ResourceCollection{}
30. #[PreserveKeys]— 在集合中保留数组键
前:
class CountryResource extends JsonResource{ public $preserveKeys = true; public function toArray(Request $request): array { return [ 'code' => $this->code, 'name' => $this->name, ]; }}
后:
use Illuminate\Http\Resources\Attributes\PreserveKeys;#[PreserveKeys]class CountryResource extends JsonResource{ public function toArray(Request $request): array { return [ 'code' => $this->code, 'name' => $this->name, ]; }}
Eloquent Factory 属性
31. #[UseModel]— 将工厂绑定到一个模型
前:
class PostFactory extends Factory{ protected $model = Post::class; public function definition(): array { return [ 'title' => fake()->sentence(), 'body' => fake()->paragraphs(3, true), ]; }}
后:
use Illuminate\Database\Eloquent\Factories\Attributes\UseModel;#[UseModel(Post::class)]class PostFactory extends Factory{ public function definition(): array { return [ 'title' => fake()->sentence(), 'body' => fake()->paragraphs(3, true), ]; }}
测试属性
32. #[Seed]— 运行测试类的默认种子程序
前:
class ProductPageTest extends TestCase{ protected $seed = true; public function test_products_page_shows_seeded_data(): void { $this->get('/products')->assertOk(); }}
后:
use Illuminate\Foundation\Testing\Attributes\Seed;#[Seed]class ProductPageTest extends TestCase{ public function test_products_page_shows_seeded_data(): void { $this->get('/products')->assertOk(); }}
33. #[Seeder]— 运行特定种子程序
前:
class AdminAccessTest extends TestCase{ protected $seeder = RoleAndPermissionSeeder::class; public function test_admin_can_access_dashboard(): void { $admin = User::factory()->admin()->create(); $this->actingAs($admin)->get('/admin')->assertOk(); }}
后:
use Illuminate\Foundation\Testing\Attributes\Seeder;#[Seeder(RoleAndPermissionSeeder::class)]class AdminAccessTest extends TestCase{ public function test_admin_can_access_dashboard(): void { $admin = User::factory()->admin()->create(); $this->actingAs($admin)->get('/admin')->assertOk(); }}
34. #[SetUp]— 将方法标记为 setUp 钩子
前:
class OrderTest extends TestCase{ private User $user; protected function setUp(): void { parent::setUp(); $this->user = User::factory()->create(); } public function test_user_can_place_order(): void { $this->actingAs($this->user) ->post('/orders', ['product_id' => 1]) ->assertCreated(); }}
后:
use Illuminate\Foundation\Testing\Attributes\SetUp;class OrderTest extends TestCase{ private User $user; #[SetUp] public function createUser(): void { $this->user = User::factory()->create(); } public function test_user_can_place_order(): void { $this->actingAs($this->user) ->post('/orders', ['product_id' => 1]) ->assertCreated(); }}
35. #[TearDown]— 将方法标记为拆卸钩
前:
class ExternalApiTest extends TestCase{ protected function tearDown(): void { Cache::tags('external-api')->flush(); parent::tearDown(); }}
后:
use Illuminate\Foundation\Testing\Attributes\TearDown;class ExternalApiTest extends TestCase{ #[TearDown] public function clearApiCache(): void { Cache::tags('external-api')->flush(); }}
预先存在的属性(Laravel 13 之前)
这些属性在 Laravel 11-12 中可用,并且在 Laravel 13 中继续有效。
Eloquent 模型属性(预先存在)
#[ObservedBy]— 附加模型观察器
use Illuminate\Database\Eloquent\Attributes\ObservedBy;#[ObservedBy(PostObserver::class)]class Post extends Model{}
#[ScopedBy]— 应用全球视野
use Illuminate\Database\Eloquent\Attributes\ScopedBy;#[ScopedBy(ActiveScope::class)]class Subscription extends Model{}
#[CollectedBy]— 使用自定义集合类
use Illuminate\Database\Eloquent\Attributes\CollectedBy;#[CollectedBy(PostCollection::class)]class Post extends Model{}
#[UseFactory]— 将模型绑定到工厂
use Illuminate\Database\Eloquent\Attributes\UseFactory;#[UseFactory(PostFactory::class)]class Post extends Model{}
#[UseEloquentBuilder]— 使用自定义查询生成器
use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;#[UseEloquentBuilder(PostBuilder::class)]class Post extends Model{}
#[UsePolicy]— 将模型绑定到策略
use Illuminate\Database\Eloquent\Attributes\UsePolicy;#[UsePolicy(PostPolicy::class)]class Post extends Model{}
#[UseResource]和#[UseResourceCollection]
use Illuminate\Database\Eloquent\Attributes\UseResource;use Illuminate\Database\Eloquent\Attributes\UseResourceCollection;#[UseResource(PostResource::class)]#[UseResourceCollection(PostCollection::class)]class Post extends Model{}
#[Boot]以及#[Initialize]——方法上的生命周期钩子
use Illuminate\Database\Eloquent\Attributes\Boot;use Illuminate\Database\Eloquent\Attributes\Initialize;class Post extends Model{ #[Boot] public static function registerEvents(): void { static::creating(fn (Post $post) => $post->slug = Str::slug($post->title)); } #[Initialize] public function setDefaults(): void { $this->attributes['status'] ??= 'draft'; }}
#[Scope]— 定义方法的局部作用域
use Illuminate\Database\Eloquent\Attributes\Scope;use Illuminate\Database\Eloquent\Builder;class Post extends Model{ #[Scope] public function published(Builder $query): void { $query->whereNotNull('published_at'); }}
队列属性(已存在)
#[DeleteWhenMissingModels]— 当模型缺失时删除作业
use Illuminate\Queue\Attributes\DeleteWhenMissingModels;#[DeleteWhenMissingModels]class SendOrderConfirmation implements ShouldQueue{ public function __construct(private Order $order) {}}
#[WithoutRelations]— 序列化前剥离关系
use Illuminate\Queue\Attributes\WithoutRelations;#[WithoutRelations]class ProcessOrder implements ShouldQueue{ public function __construct(private Order $order) {}}
容器/依赖注入属性
这些用于构造函数或方法参数,以控制依赖项的解析方式。
#[CurrentUser]—注入已验证用户
use Illuminate\Container\Attributes\CurrentUser;class DashboardController extends Controller{ public function index(#[CurrentUser] User $user) { return view('dashboard', compact('user')); }}
#[Config]— 注入配置值
use Illuminate\Container\Attributes\Config;class PaymentService{ public function __construct( #[Config('services.stripe.secret')] private string $stripeSecret, ) { }}
#[Auth]— 注入身份验证守卫
use Illuminate\Container\Attributes\Auth;use Illuminate\Contracts\Auth\Guard;class ApiController extends Controller{ public function __construct( #[Auth('api')] private Guard $auth, ) { }}
#[Cache]— 注入缓存存储
use Illuminate\Container\Attributes\Cache;use Illuminate\Contracts\Cache\Repository;class ReportService{ public function __construct( #[Cache('redis')] private Repository $cache, ) { }}
#[DB]— 注入数据库连接
use Illuminate\Container\Attributes\DB;use Illuminate\Database\Connection;class AnalyticsService{ public function __construct( #[DB('analytics')] private Connection $db, ) { }}
#[Log]— 注入日志通道
use Illuminate\Container\Attributes\Log;use Psr\Log\LoggerInterface;class PaymentService{ public function __construct( #[Log('payments')] private LoggerInterface $logger, ) { }}
#[Storage]— 注入文件系统磁盘
use Illuminate\Container\Attributes\Storage;use Illuminate\Contracts\Filesystem\Filesystem;class UploadService{ public function __construct( #[Storage('s3')] private Filesystem $disk, ) { }}
#[Tag]— 注入标签服务
use Illuminate\Container\Attributes\Tag;class NotificationSender{ public function __construct( #[Tag('notification.channels')] private iterable $channels, ) { }}
#[RouteParameter]— 注入路由参数
use Illuminate\Container\Attributes\RouteParameter;class InvoiceController extends Controller{ public function show(#[RouteParameter('invoice')] string $invoiceId) { // ... }}
#[Give]— 提供具体实施方案
use Illuminate\Container\Attributes\Give;class OrderProcessor{ public function __construct( #[Give(StripePaymentGateway::class)] private PaymentGateway $gateway, ) { }}
#[Authenticated]— 注入已认证用户(通过 Guard)
use Illuminate\Container\Attributes\Authenticated;use Illuminate\Contracts\Auth\Authenticatable;class ProfileController extends Controller{ public function edit(#[Authenticated('web')] Authenticatable $user) { return view('profile.edit', compact('user')); }}
#[Context]— 从上下文存储库注入
use Illuminate\Container\Attributes\Context;class RequestHandler{ public function __construct( #[Context('request_id')] private string $requestId, ) { }}
#[Database]— 注入数据库连接(别名)
use Illuminate\Container\Attributes\Database;use Illuminate\Database\Connection;class LegacyService{ public function __construct( #[Database('legacy_mysql')] private Connection $db, ) { }}
容器/服务注册属性
这些用于类定义中,以控制服务的注册方式。
#[Bind]— 将类自动绑定到容器
use Illuminate\Container\Attributes\Bind;#[Bind]class InvoiceGenerator{ public function generate(Order $order): Invoice { // A new instance is created each time it's resolved }}
#[Singleton]— 注册为单户
use Illuminate\Container\Attributes\Singleton;#[Singleton]class FeatureFlagService{ private array $flags = []; public function isEnabled(string $flag): bool { return $this->flags[$flag] ?? false; }}
#[Scoped]— 注册为作用域实例
use Illuminate\Container\Attributes\Scoped;#[Scoped]class RequestContext{ public ?string $traceId = null;}
概括
Laravel 13 新增了36 个属性类,使属性类总数超过 50 个。其中最大的亮点包括:
- 模型属性(
#[Fillable]例如,,,等等)——更简洁的模型定义#[Table],#[Hidden]无需属性样板文本 - 作业属性(
#[Tries]例如,,,等等)— 使用属性完全配置作业#[Timeout]。#[Queue] - 控制台属性(
#[Signature],#[Description])— 定义不带字符串属性的命令 - 控制器属性(
#[Middleware],#[Authorize])— 以声明方式附加中间件和授权
传统的基于属性的方法仍然有效。属性是一种替代方案,而非替代品。选择团队偏好的风格并保持一致即可。




