laravel-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLaravel 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-docsLaravel 最佳实践,按影响优先级排序。每条规则会说明操作方法及原因。如需确切的API语法,请通过验证。
search-docsConsistency 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
rules/db-performance.md1. 数据库性能 → rules/db-performance.md
rules/db-performance.md- Eager load with to prevent N+1 queries
with() - Enable in development
Model::preventLazyLoading() - Select only needed columns, avoid
SELECT * - /
chunk()for large datasetschunkById() - Index columns used in ,
WHERE,ORDER BYJOIN - instead of loading relations to count
withCount() - for memory-efficient read-only iteration
cursor() - Never query in Blade templates
- 使用预加载以避免N+1查询
with() - 在开发环境中启用
Model::preventLazyLoading() - 仅选择所需列,避免
SELECT * - 对大型数据集使用/
chunk()chunkById() - 为、
WHERE、ORDER BY中使用的列创建索引JOIN - 使用替代加载关联关系来统计数量
withCount() - 使用进行内存高效的只读迭代
cursor() - 绝不在Blade模板中执行查询
2. Advanced Query Patterns → rules/advanced-queries.md
rules/advanced-queries.md2. 高级查询模式 → rules/advanced-queries.md
rules/advanced-queries.md- subqueries over eager-loading entire has-many for a single value
addSelect() - Dynamic relationships via subquery FK +
belongsTo - Conditional aggregates (in
CASE WHEN) over multiple count queriesselectRaw - to prevent circular N+1 queries
setRelation() - +
whereInoverpluck()for better index usagewhereHas - Two simple queries can beat one complex query
- Compound indexes matching column order
orderBy - Correlated subqueries in for has-many sorting (avoid joins)
orderBy
- 对于单个值,使用子查询而非预加载整个一对多关联
addSelect() - 通过子查询外键 + 实现动态关联
belongsTo - 使用条件聚合(中的
selectRaw)替代多个统计查询CASE WHEN - 使用避免循环N+1查询
setRelation() - 为提升索引使用率,优先使用+
whereIn而非pluck()whereHas - 两个简单查询可能优于一个复杂查询
- 创建与列顺序匹配的复合索引
orderBy - 在中使用关联子查询对一对多数据排序(避免使用连接)
orderBy
3. Security → rules/security.md
rules/security.md3. 安全 → rules/security.md
rules/security.md- Define or
$fillableon every model, authorize every action via policies or gates$guarded - No raw SQL with user input — use Eloquent or query builder
- for output escaping,
{{ }}on all POST/PUT/DELETE forms,@csrfon auth and API routesthrottle - Validate MIME type, extension, and size for file uploads
- Never commit , use
.envfor secrets,config()cast for sensitive DB fieldsencrypted
- 在每个模型上定义或
$fillable,通过策略或门控授权每个操作$guarded - 不要在包含用户输入的原生SQL中使用——使用Eloquent或查询构建器
- 使用进行输出转义,在所有POST/PUT/DELETE表单上添加
{{ }},在认证和API路由上使用@csrfthrottle - 验证文件上传的MIME类型、扩展名和大小
- 绝不要提交文件,使用
.env获取密钥,对敏感数据库字段使用config()类型转换encrypted
4. Caching → rules/caching.md
rules/caching.md4. 缓存 → rules/caching.md
rules/caching.md- over manual get/put
Cache::remember() - for stale-while-revalidate on high-traffic data
Cache::flexible() - to avoid redundant cache hits within a request
Cache::memo() - Cache tags to invalidate related groups
- for atomic conditional writes
Cache::add() - to memoize per-request or per-object lifetime
once() - /
Cache::lock()for race conditionslockForUpdate() - Failover cache stores in production
- 使用替代手动执行get/put操作
Cache::remember() - 对高流量数据使用实现 stale-while-revalidate 策略
Cache::flexible() - 使用避免请求内重复缓存命中
Cache::memo() - 使用缓存标签使相关缓存组失效
- 使用实现原子条件写入
Cache::add() - 使用在请求或对象生命周期内进行记忆化
once() - 使用/
Cache::lock()处理竞态条件lockForUpdate() - 在生产环境中使用故障转移缓存存储
5. Eloquent Patterns → rules/eloquent.md
rules/eloquent.md5. Eloquent 模式 → rules/eloquent.md
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 method
casts() - Cast date columns, use Carbon instances in templates
- for cleaner queries
whereBelongsTo($model) - Never hardcode table names — use or Eloquent queries
(new Model)->getTable()
- 正确设置关联关系类型并添加返回类型提示
- 使用本地作用域实现可复用的查询约束
- 谨慎使用全局作用域——需记录其存在
- 在方法中定义属性类型转换
casts() - 对日期列进行类型转换,在模板中使用Carbon实例
- 使用编写更简洁的查询
whereBelongsTo($model) - 绝不要硬编码表名——使用或Eloquent查询
(new Model)->getTable()
6. Validation & Forms → rules/validation.md
rules/validation.md6. 验证与表单 → rules/validation.md
rules/validation.md- Form Request classes, not inline validation
- Array notation for new code; follow existing convention
['required', 'email'] - only — never
$request->validated()$request->all() - for conditional validation
Rule::when() - instead of
after()withValidator()
- 使用表单请求类,而非内联验证
- 新代码使用数组表示法;遵循现有约定
['required', 'email'] - 仅使用——绝不使用
$request->validated()$request->all() - 使用实现条件验证
Rule::when() - 使用替代
after()withValidator()
7. Configuration → rules/config.md
rules/config.md7. 配置 → rules/config.md
rules/config.md- only inside config files
env() - or
App::environment()app()->isProduction() - Config, lang files, and constants over hardcoded text
- 仅在配置文件中使用
env() - 使用或
App::environment()判断环境app()->isProduction() - 使用配置、语言文件和常量替代硬编码文本
8. Testing Patterns → rules/testing.md
rules/testing.md8. 测试模式 → rules/testing.md
rules/testing.md- over
LazilyRefreshDatabasefor speedRefreshDatabase - over raw
assertModelExists()assertDatabaseHas() - Factory states and sequences over manual overrides
- Use fakes (,
Event::fake(), etc.) — but always after factory setup, not beforeExceptions::fake() - to share relationship instances across factories
recycle()
- 为提升速度,使用替代
LazilyRefreshDatabaseRefreshDatabase - 使用替代原生
assertModelExists()assertDatabaseHas() - 使用工厂状态和序列替代手动覆盖
- 使用假对象(、
Event::fake()等)——但务必在工厂设置之后使用,而非之前Exceptions::fake() - 使用在工厂间共享关联实例
recycle()
9. Queue & Job Patterns → rules/queue-jobs.md
rules/queue-jobs.md9. 队列与任务模式 → rules/queue-jobs.md
rules/queue-jobs.md- must exceed job
retry_after; use exponential backofftimeout[1, 5, 10] - to prevent duplicates;
ShouldBeUniquefor concurrencyWithoutOverlapping::untilProcessing() - Always implement ; with
failed(), setretryUntil()$tries = 0 - middleware for external API calls;
RateLimitedfor related jobsBus::batch() - 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
rules/routing.md10. 路由与控制器 → rules/routing.md
rules/routing.md- Implicit route model binding
- Scoped bindings for nested resources
- or
Route::resource()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
rules/http-client.md11. HTTP客户端 → rules/http-client.md
rules/http-client.md- Explicit and
timeouton every requestconnectTimeout - with exponential backoff for external APIs
retry() - Check response status or use
throw() - for concurrent independent requests
Http::pool() - and
Http::fake()in testspreventStrayRequests()
- 在每个请求上显式设置和
timeoutconnectTimeout - 对外部API使用带指数退避的
retry() - 检查响应状态或使用
throw() - 使用处理并发独立请求
Http::pool() - 在测试中使用和
Http::fake()preventStrayRequests()
12. Events, Notifications & Mail → rules/events-notifications.md
, rules/mail.md
rules/events-notifications.mdrules/mail.md12. 事件、通知与邮件 → rules/events-notifications.md
, rules/mail.md
rules/events-notifications.mdrules/mail.md- Event discovery over manual registration; in production
event:cache - /
ShouldDispatchAfterCommitinside transactionsafterCommit() - Queue notifications and mailables with
ShouldQueue - On-demand notifications for non-user recipients
- on notifiable models
HasLocalePreference - not
assertQueued()for queued mailablesassertSent() - Markdown mailables for transactional emails
- 使用事件发现替代手动注册;在生产环境中执行
event:cache - 在事务中使用/
ShouldDispatchAfterCommitafterCommit() - 使用将通知和邮件加入队列
ShouldQueue - 为非用户收件人使用按需通知
- 在可通知模型上实现
HasLocalePreference - 对队列化邮件使用而非
assertQueued()assertSent() - 对事务性邮件使用Markdown邮件
13. Error Handling → rules/error-handling.md
rules/error-handling.md13. 错误处理 → rules/error-handling.md
rules/error-handling.md- /
report()on exception classes or inrender()— follow existing patternbootstrap/app.php - for exceptions that should never log
ShouldntReport - Throttle high-volume exceptions to protect log sinks
- for multi-catch scenarios
dontReportDuplicates() - Force JSON rendering for API routes
- Structured context via on exception classes
context()
- 在异常类或中实现
bootstrap/app.php/report()——遵循现有模式render() - 对不应记录的异常使用
ShouldntReport - 对高频率异常进行限流以保护日志存储
- 在多捕获场景中使用
dontReportDuplicates() - 强制API路由返回JSON格式
- 通过异常类上的添加结构化上下文
context()
14. Task Scheduling → rules/scheduling.md
rules/scheduling.md14. 任务调度 → rules/scheduling.md
rules/scheduling.md- on variable-duration tasks
withoutOverlapping() - on multi-server deployments
onOneServer() - for concurrent long tasks
runInBackground() - to restrict to appropriate environments
environments() - for time-bounded processing
takeUntilTimeout() - Schedule groups for shared configuration
- 对时长不固定的任务使用
withoutOverlapping() - 在多服务器部署中使用
onOneServer() - 对长时间并发任务使用
runInBackground() - 使用限制运行环境
environments() - 对限时处理任务使用
takeUntilTimeout() - 使用调度组共享配置
15. Architecture → rules/architecture.md
rules/architecture.md15. 架构 → rules/architecture.md
rules/architecture.md- Single-purpose Action classes; dependency injection over helper
app() - Prefer official Laravel packages and follow conventions, don't override defaults
- Default to or
ORDER BY id DESC;created_at DESCfor UTF-8 safetymb_* - for post-response work;
defer()for request-scoped data;Contextfor parallel executionConcurrency::run()
- 单一职责的动作类;使用依赖注入而非助手函数
app() - 优先使用官方Laravel包并遵循约定,不要覆盖默认设置
- 默认使用或
ORDER BY id DESC;使用created_at DESC函数确保UTF-8安全mb_* - 使用处理响应后工作;使用
defer()存储请求作用域数据;使用Context实现并行执行Concurrency::run()
16. Migrations → rules/migrations.md
rules/migrations.md16. 迁移 → rules/migrations.md
rules/migrations.md- Generate migrations with
php artisan make:migration - for foreign keys
constrained() - Never modify migrations that have run in production
- Add indexes in the migration, not as an afterthought
- Mirror column defaults in model
$attributes - Reversible by default; forward-fix migrations for intentionally irreversible changes
down() - One concern per migration — never mix DDL and DML
- 使用生成迁移文件
php artisan make:migration - 对外键使用
constrained() - 绝不要修改已在生产环境中执行过的迁移文件
- 在迁移中添加索引,不要事后补充
- 在模型中镜像列默认值
$attributes - 默认实现可逆的;对于有意不可逆的变更,使用向前修复的迁移
down() - 每个迁移只处理一个关注点——绝不要混合DDL和DML操作
17. Collections → rules/collections.md
rules/collections.md17. 集合 → rules/collections.md
rules/collections.md- Higher-order messages for simple collection operations
- vs.
cursor()— choose based on relationship needslazy() - when updating records while iterating
lazyById() - for bulk operations on collections
toQuery()
- 对简单集合操作使用高阶消息
- 根据关联需求选择vs.
cursor()lazy() - 在迭代时更新记录使用
lazyById() - 对集合使用执行批量操作
toQuery()
18. Blade & Views → rules/blade-views.md
rules/blade-views.md18. Blade与视图 → rules/blade-views.md
rules/blade-views.md- in component templates
$attributes->merge() - Blade components over ;
@includefor per-component scripts@pushOnce - View Composers for shared view data
- for deeply nested component props
@aware
- 在组件模板中使用
$attributes->merge() - 优先使用Blade组件而非;使用
@include处理每个组件的脚本@pushOnce - 使用视图合成器共享视图数据
- 对深度嵌套的组件属性使用
@aware
19. Conventions & Style → rules/style.md
rules/style.md19. 约定与风格 → rules/style.md
rules/style.md- Follow Laravel naming conventions for all entities
- Prefer Laravel helpers (,
Str,Arr,Number,Uri,Str::of()) over raw PHP functions$request->string() - 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())而非原生PHP函数$request->string() - 不要在Blade中编写JS/CSS,不要在PHP类中编写HTML
- 代码应具备可读性;仅在配置文件中添加注释
How to Apply
应用方法
Always use a sub-agent to read rule files and explore this skill's content.
- Identify the file type and select relevant sections (e.g., migration → §16, controller → §1, §3, §5, §6, §10)
- Check sibling files for existing patterns — follow those first per Consistency First
- Verify API syntax with for the installed Laravel version
search-docs
始终使用子代理读取规则文件并探索此技能的内容。
- 确定文件类型并选择相关章节(例如:迁移→第16节,控制器→第1、3、5、6、10节)
- 检查同级文件中的现有模式——首先遵循“一致性优先”原则
- 针对已安装的Laravel版本,通过验证API语法
search-docs