laravel-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Laravel Best Practices

Laravel 最佳实践

Best practices for Laravel, prioritized by impact. Each rule teaches what to do and why. For exact API syntax, verify with
search-docs
.
Laravel 最佳实践,按影响优先级排序。每条规则会说明操作方法及原因。如需确切的API语法,请通过
search-docs
验证。

Consistency First

一致性优先

Before applying any rule, check what the application already does. Laravel offers multiple valid approaches — the best choice is the one the codebase already uses, even if another pattern would be theoretically better. Inconsistency is worse than a suboptimal pattern.
Check sibling files, related controllers, models, or tests for established patterns. If one exists, follow it — don't introduce a second way. These rules are defaults for when no pattern exists yet, not overrides.
在应用任何规则之前,请先查看应用程序已有的实现方式。Laravel提供多种有效方案——最佳选择是代码库已在使用的方案,即便其他模式在理论上更优。不一致性比次优模式的危害更大。
检查同级文件、相关控制器、模型或测试中已确立的模式。如果存在既定模式,请遵循它——不要引入第二种方式。这些规则是在尚无模式时的默认方案,而非覆盖现有模式的规则。

Quick Reference

快速参考

1. Database Performance →
rules/db-performance.md

1. 数据库性能 →
rules/db-performance.md

  • Eager load with
    with()
    to prevent N+1 queries
  • Enable
    Model::preventLazyLoading()
    in development
  • Select only needed columns, avoid
    SELECT *
  • chunk()
    /
    chunkById()
    for large datasets
  • Index columns used in
    WHERE
    ,
    ORDER BY
    ,
    JOIN
  • withCount()
    instead of loading relations to count
  • cursor()
    for memory-efficient read-only iteration
  • Never query in Blade templates
  • 使用
    with()
    预加载以避免N+1查询
  • 在开发环境中启用
    Model::preventLazyLoading()
  • 仅选择所需列,避免
    SELECT *
  • 对大型数据集使用
    chunk()
    /
    chunkById()
  • WHERE
    ORDER BY
    JOIN
    中使用的列创建索引
  • 使用
    withCount()
    替代加载关联关系来统计数量
  • 使用
    cursor()
    进行内存高效的只读迭代
  • 绝不在Blade模板中执行查询

2. Advanced Query Patterns →
rules/advanced-queries.md

2. 高级查询模式 →
rules/advanced-queries.md

  • addSelect()
    subqueries over eager-loading entire has-many for a single value
  • Dynamic relationships via subquery FK +
    belongsTo
  • Conditional aggregates (
    CASE WHEN
    in
    selectRaw
    ) over multiple count queries
  • setRelation()
    to prevent circular N+1 queries
  • whereIn
    +
    pluck()
    over
    whereHas
    for better index usage
  • Two simple queries can beat one complex query
  • Compound indexes matching
    orderBy
    column order
  • Correlated subqueries in
    orderBy
    for has-many sorting (avoid joins)
  • 对于单个值,使用
    addSelect()
    子查询而非预加载整个一对多关联
  • 通过子查询外键 +
    belongsTo
    实现动态关联
  • 使用条件聚合(
    selectRaw
    中的
    CASE WHEN
    )替代多个统计查询
  • 使用
    setRelation()
    避免循环N+1查询
  • 为提升索引使用率,优先使用
    whereIn
    +
    pluck()
    而非
    whereHas
  • 两个简单查询可能优于一个复杂查询
  • 创建与
    orderBy
    列顺序匹配的复合索引
  • orderBy
    中使用关联子查询对一对多数据排序(避免使用连接)

3. Security →
rules/security.md

3. 安全 →
rules/security.md

  • Define
    $fillable
    or
    $guarded
    on every model, authorize every action via policies or gates
  • No raw SQL with user input — use Eloquent or query builder
  • {{ }}
    for output escaping,
    @csrf
    on all POST/PUT/DELETE forms,
    throttle
    on auth and API routes
  • Validate MIME type, extension, and size for file uploads
  • Never commit
    .env
    , use
    config()
    for secrets,
    encrypted
    cast for sensitive DB fields
  • 在每个模型上定义
    $fillable
    $guarded
    ,通过策略或门控授权每个操作
  • 不要在包含用户输入的原生SQL中使用——使用Eloquent或查询构建器
  • 使用
    {{ }}
    进行输出转义,在所有POST/PUT/DELETE表单上添加
    @csrf
    ,在认证和API路由上使用
    throttle
  • 验证文件上传的MIME类型、扩展名和大小
  • 绝不要提交
    .env
    文件,使用
    config()
    获取密钥,对敏感数据库字段使用
    encrypted
    类型转换

4. Caching →
rules/caching.md

4. 缓存 →
rules/caching.md

  • Cache::remember()
    over manual get/put
  • Cache::flexible()
    for stale-while-revalidate on high-traffic data
  • Cache::memo()
    to avoid redundant cache hits within a request
  • Cache tags to invalidate related groups
  • Cache::add()
    for atomic conditional writes
  • once()
    to memoize per-request or per-object lifetime
  • Cache::lock()
    /
    lockForUpdate()
    for race conditions
  • Failover cache stores in production
  • 使用
    Cache::remember()
    替代手动执行get/put操作
  • 对高流量数据使用
    Cache::flexible()
    实现 stale-while-revalidate 策略
  • 使用
    Cache::memo()
    避免请求内重复缓存命中
  • 使用缓存标签使相关缓存组失效
  • 使用
    Cache::add()
    实现原子条件写入
  • 使用
    once()
    在请求或对象生命周期内进行记忆化
  • 使用
    Cache::lock()
    /
    lockForUpdate()
    处理竞态条件
  • 在生产环境中使用故障转移缓存存储

5. Eloquent Patterns →
rules/eloquent.md

5. Eloquent 模式 →
rules/eloquent.md

  • Correct relationship types with return type hints
  • Local scopes for reusable query constraints
  • Global scopes sparingly — document their existence
  • Attribute casts in the
    casts()
    method
  • Cast date columns, use Carbon instances in templates
  • whereBelongsTo($model)
    for cleaner queries
  • Never hardcode table names — use
    (new Model)->getTable()
    or Eloquent queries
  • 正确设置关联关系类型并添加返回类型提示
  • 使用本地作用域实现可复用的查询约束
  • 谨慎使用全局作用域——需记录其存在
  • casts()
    方法中定义属性类型转换
  • 对日期列进行类型转换,在模板中使用Carbon实例
  • 使用
    whereBelongsTo($model)
    编写更简洁的查询
  • 绝不要硬编码表名——使用
    (new Model)->getTable()
    或Eloquent查询

6. Validation & Forms →
rules/validation.md

6. 验证与表单 →
rules/validation.md

  • Form Request classes, not inline validation
  • Array notation
    ['required', 'email']
    for new code; follow existing convention
  • $request->validated()
    only — never
    $request->all()
  • Rule::when()
    for conditional validation
  • after()
    instead of
    withValidator()
  • 使用表单请求类,而非内联验证
  • 新代码使用数组表示法
    ['required', 'email']
    ;遵循现有约定
  • 仅使用
    $request->validated()
    ——绝不使用
    $request->all()
  • 使用
    Rule::when()
    实现条件验证
  • 使用
    after()
    替代
    withValidator()

7. Configuration →
rules/config.md

7. 配置 →
rules/config.md

  • env()
    only inside config files
  • App::environment()
    or
    app()->isProduction()
  • Config, lang files, and constants over hardcoded text
  • 仅在配置文件中使用
    env()
  • 使用
    App::environment()
    app()->isProduction()
    判断环境
  • 使用配置、语言文件和常量替代硬编码文本

8. Testing Patterns →
rules/testing.md

8. 测试模式 →
rules/testing.md

  • LazilyRefreshDatabase
    over
    RefreshDatabase
    for speed
  • assertModelExists()
    over raw
    assertDatabaseHas()
  • Factory states and sequences over manual overrides
  • Use fakes (
    Event::fake()
    ,
    Exceptions::fake()
    , etc.) — but always after factory setup, not before
  • recycle()
    to share relationship instances across factories
  • 为提升速度,使用
    LazilyRefreshDatabase
    替代
    RefreshDatabase
  • 使用
    assertModelExists()
    替代原生
    assertDatabaseHas()
  • 使用工厂状态和序列替代手动覆盖
  • 使用假对象(
    Event::fake()
    Exceptions::fake()
    等)——但务必在工厂设置之后使用,而非之前
  • 使用
    recycle()
    在工厂间共享关联实例

9. Queue & Job Patterns →
rules/queue-jobs.md

9. 队列与任务模式 →
rules/queue-jobs.md

  • retry_after
    must exceed job
    timeout
    ; use exponential backoff
    [1, 5, 10]
  • ShouldBeUnique
    to prevent duplicates;
    WithoutOverlapping::untilProcessing()
    for concurrency
  • Always implement
    failed()
    ; with
    retryUntil()
    , set
    $tries = 0
  • RateLimited
    middleware for external API calls;
    Bus::batch()
    for related jobs
  • Horizon for complex multi-queue scenarios
  • retry_after
    必须大于任务
    timeout
    ;使用指数退避
    [1, 5, 10]
  • 使用
    ShouldBeUnique
    避免重复;使用
    WithoutOverlapping::untilProcessing()
    控制并发
  • 始终实现
    failed()
    ;若使用
    retryUntil()
    ,需设置
    $tries = 0
  • 对外部API调用使用
    RateLimited
    中间件;使用
    Bus::batch()
    处理相关任务
  • 对于复杂的多队列场景使用Horizon

10. Routing & Controllers →
rules/routing.md

10. 路由与控制器 →
rules/routing.md

  • Implicit route model binding
  • Scoped bindings for nested resources
  • Route::resource()
    or
    apiResource()
  • Methods under 10 lines — extract to actions/services
  • Type-hint Form Requests for auto-validation
  • 隐式路由模型绑定
  • 对嵌套资源使用范围绑定
  • 使用
    Route::resource()
    apiResource()
  • 方法代码不超过10行——提取到动作/服务类中
  • 对表单请求进行类型提示以实现自动验证

11. HTTP Client →
rules/http-client.md

11. HTTP客户端 →
rules/http-client.md

  • Explicit
    timeout
    and
    connectTimeout
    on every request
  • retry()
    with exponential backoff for external APIs
  • Check response status or use
    throw()
  • Http::pool()
    for concurrent independent requests
  • Http::fake()
    and
    preventStrayRequests()
    in tests
  • 在每个请求上显式设置
    timeout
    connectTimeout
  • 对外部API使用带指数退避的
    retry()
  • 检查响应状态或使用
    throw()
  • 使用
    Http::pool()
    处理并发独立请求
  • 在测试中使用
    Http::fake()
    preventStrayRequests()

12. Events, Notifications & Mail →
rules/events-notifications.md
,
rules/mail.md

12. 事件、通知与邮件 →
rules/events-notifications.md
,
rules/mail.md

  • Event discovery over manual registration;
    event:cache
    in production
  • ShouldDispatchAfterCommit
    /
    afterCommit()
    inside transactions
  • Queue notifications and mailables with
    ShouldQueue
  • On-demand notifications for non-user recipients
  • HasLocalePreference
    on notifiable models
  • assertQueued()
    not
    assertSent()
    for queued mailables
  • Markdown mailables for transactional emails
  • 使用事件发现替代手动注册;在生产环境中执行
    event:cache
  • 在事务中使用
    ShouldDispatchAfterCommit
    /
    afterCommit()
  • 使用
    ShouldQueue
    将通知和邮件加入队列
  • 为非用户收件人使用按需通知
  • 在可通知模型上实现
    HasLocalePreference
  • 对队列化邮件使用
    assertQueued()
    而非
    assertSent()
  • 对事务性邮件使用Markdown邮件

13. Error Handling →
rules/error-handling.md

13. 错误处理 →
rules/error-handling.md

  • report()
    /
    render()
    on exception classes or in
    bootstrap/app.php
    — follow existing pattern
  • ShouldntReport
    for exceptions that should never log
  • Throttle high-volume exceptions to protect log sinks
  • dontReportDuplicates()
    for multi-catch scenarios
  • Force JSON rendering for API routes
  • Structured context via
    context()
    on exception classes
  • 在异常类或
    bootstrap/app.php
    中实现
    report()
    /
    render()
    ——遵循现有模式
  • 对不应记录的异常使用
    ShouldntReport
  • 对高频率异常进行限流以保护日志存储
  • 在多捕获场景中使用
    dontReportDuplicates()
  • 强制API路由返回JSON格式
  • 通过异常类上的
    context()
    添加结构化上下文

14. Task Scheduling →
rules/scheduling.md

14. 任务调度 →
rules/scheduling.md

  • withoutOverlapping()
    on variable-duration tasks
  • onOneServer()
    on multi-server deployments
  • runInBackground()
    for concurrent long tasks
  • environments()
    to restrict to appropriate environments
  • takeUntilTimeout()
    for time-bounded processing
  • Schedule groups for shared configuration
  • 对时长不固定的任务使用
    withoutOverlapping()
  • 在多服务器部署中使用
    onOneServer()
  • 对长时间并发任务使用
    runInBackground()
  • 使用
    environments()
    限制运行环境
  • 对限时处理任务使用
    takeUntilTimeout()
  • 使用调度组共享配置

15. Architecture →
rules/architecture.md

15. 架构 →
rules/architecture.md

  • Single-purpose Action classes; dependency injection over
    app()
    helper
  • Prefer official Laravel packages and follow conventions, don't override defaults
  • Default to
    ORDER BY id DESC
    or
    created_at DESC
    ;
    mb_*
    for UTF-8 safety
  • defer()
    for post-response work;
    Context
    for request-scoped data;
    Concurrency::run()
    for parallel execution
  • 单一职责的动作类;使用依赖注入而非
    app()
    助手函数
  • 优先使用官方Laravel包并遵循约定,不要覆盖默认设置
  • 默认使用
    ORDER BY id DESC
    created_at DESC
    ;使用
    mb_*
    函数确保UTF-8安全
  • 使用
    defer()
    处理响应后工作;使用
    Context
    存储请求作用域数据;使用
    Concurrency::run()
    实现并行执行

16. Migrations →
rules/migrations.md

16. 迁移 →
rules/migrations.md

  • Generate migrations with
    php artisan make:migration
  • constrained()
    for foreign keys
  • Never modify migrations that have run in production
  • Add indexes in the migration, not as an afterthought
  • Mirror column defaults in model
    $attributes
  • Reversible
    down()
    by default; forward-fix migrations for intentionally irreversible changes
  • One concern per migration — never mix DDL and DML
  • 使用
    php artisan make:migration
    生成迁移文件
  • 对外键使用
    constrained()
  • 绝不要修改已在生产环境中执行过的迁移文件
  • 在迁移中添加索引,不要事后补充
  • 在模型
    $attributes
    中镜像列默认值
  • 默认实现可逆的
    down()
    ;对于有意不可逆的变更,使用向前修复的迁移
  • 每个迁移只处理一个关注点——绝不要混合DDL和DML操作

17. Collections →
rules/collections.md

17. 集合 →
rules/collections.md

  • Higher-order messages for simple collection operations
  • cursor()
    vs.
    lazy()
    — choose based on relationship needs
  • lazyById()
    when updating records while iterating
  • toQuery()
    for bulk operations on collections
  • 对简单集合操作使用高阶消息
  • 根据关联需求选择
    cursor()
    vs.
    lazy()
  • 在迭代时更新记录使用
    lazyById()
  • 对集合使用
    toQuery()
    执行批量操作

18. Blade & Views →
rules/blade-views.md

18. Blade与视图 →
rules/blade-views.md

  • $attributes->merge()
    in component templates
  • Blade components over
    @include
    ;
    @pushOnce
    for per-component scripts
  • View Composers for shared view data
  • @aware
    for deeply nested component props
  • 在组件模板中使用
    $attributes->merge()
  • 优先使用Blade组件而非
    @include
    ;使用
    @pushOnce
    处理每个组件的脚本
  • 使用视图合成器共享视图数据
  • 对深度嵌套的组件属性使用
    @aware

19. Conventions & Style →
rules/style.md

19. 约定与风格 →
rules/style.md

  • Follow Laravel naming conventions for all entities
  • Prefer Laravel helpers (
    Str
    ,
    Arr
    ,
    Number
    ,
    Uri
    ,
    Str::of()
    ,
    $request->string()
    ) over raw PHP functions
  • No JS/CSS in Blade, no HTML in PHP classes
  • Code should be readable; comments only for config files
  • 对所有实体遵循Laravel命名约定
  • 优先使用Laravel助手函数(
    Str
    Arr
    Number
    Uri
    Str::of()
    $request->string()
    )而非原生PHP函数
  • 不要在Blade中编写JS/CSS,不要在PHP类中编写HTML
  • 代码应具备可读性;仅在配置文件中添加注释

How to Apply

应用方法

Always use a sub-agent to read rule files and explore this skill's content.
  1. Identify the file type and select relevant sections (e.g., migration → §16, controller → §1, §3, §5, §6, §10)
  2. Check sibling files for existing patterns — follow those first per Consistency First
  3. Verify API syntax with
    search-docs
    for the installed Laravel version
始终使用子代理读取规则文件并探索此技能的内容。
  1. 确定文件类型并选择相关章节(例如:迁移→第16节,控制器→第1、3、5、6、10节)
  2. 检查同级文件中的现有模式——首先遵循“一致性优先”原则
  3. 针对已安装的Laravel版本,通过
    search-docs
    验证API语法