这并非laravel官方强制要求的规范,而是我们在日常开发过程中遇到的一些容易忽视的优秀实现方式。
内容
注释你的代码,但是更优雅的做法是使用描述性的语言来编写你的代码
不要把 JS 和 CSS 放到 Blade 模板中,也不要把任何 HTML 代码放到 PHP 代码里
单一职责原则
一个类和一个方法应该只有一个责任。
例如:
1 | public function getFullNameAttribute() |
更优的写法:
1 | public function getFullNameAttribute() |
保持控制器的简洁
如果您使用的是查询生成器或原始SQL查询,请将所有与数据库相关的逻辑放入Eloquent模型或Repository类中。
例如:
1 | public function index() |
更优的写法:
1 | public function index() |
使用自定义Request类来进行验证
把验证规则放到 Request 类中.
例子:
1 | public function store(Request $request) |
更优的写法:
1 | public function store(PostRequest $request) |
业务代码要放到服务层中
控制器必须遵循单一职责原则,因此最好将业务代码从控制器移动到服务层中。
例子:
1 | public function store(Request $request) |
更优的写法:
1 | public function store(Request $request) |
DRY原则 不要重复自己
尽可能重用代码,SRP可以帮助您避免重复造轮子。 此外尽量重复使用Blade模板,使用Eloquent的 scopes 方法来实现代码。
例子:
1 | public function getActive() |
更优的写法:
1 | public function scopeActive($q) |
使用ORM而不是纯sql语句,使用集合而不是数组
使用Eloquent可以帮您编写可读和可维护的代码。 此外Eloquent还有非常优雅的内置工具,如软删除,事件,范围等。
例子:
1 | SELECT * |
更优的写法:
1 | Article::has('user.profile')->verified()->latest()->get(); |
集中处理数据
例子:
1 | $article = new Article; |
更优的写法:
1 | $category->article()->create($request->validated()); |
不要在模板中查询,尽量使用惰性加载
例子 (对于100个用户,将执行101次DB查询):
1 | @foreach (User::all() as $user) |
更优的写法 (对于100个用户,使用以下写法只需执行2次DB查询):
1 | $users = User::with('profile')->get(); |
注释你的代码,但是更优雅的做法是使用描述性的语言来编写你的代码
例子:
1 | if (count((array) $builder->getQuery()->joins) > 0) |
加上注释:
1 | // 确定是否有任何连接 |
更优的写法:
1 | if ($this->hasJoins()) |
不要把 JS 和 CSS 放到 Blade 模板中,也不要把任何 HTML 代码放到 PHP 代码里
例子:
1 | let article = `{{ json_encode($article) }}`; |
更好的写法:
1 | <input id="article" type="hidden" value="@json($article)"> |
在Javascript文件中加上:
1 | let article = $('#article').val(); |
当然最好的办法还是使用专业的PHP的JS包传输数据。
在代码中使用配置、语言包和常量,而不是使用硬编码
例子:
1 | public function isNormal() |
更优的写法:
1 | public function isNormal() |
使用社区认可的标准Laravel工具
强力推荐使用内置的Laravel功能和扩展包,而不是使用第三方的扩展包和工具。
如果你的项目被其他开发人员接手了,他们将不得不重新学习这些第三方工具的使用教程。
此外,当您使用第三方扩展包或工具时,你很难从Laravel社区获得什么帮助。 不要让你的客户为额外的问题付钱。
想要实现的功能 | 标准工具 | 第三方工具 |
---|---|---|
权限 | Policies | Entrust, Sentinel 或者其他扩展包 |
资源编译工具 | Laravel Mix | Grunt, Gulp, 或者其他第三方包 |
开发环境 | Homestead | Docker |
部署 | Laravel Forge | Deployer 或者其他解决方案 |
自动化测试 | PHPUnit, Mockery | Phpspec |
页面预览测试 | Laravel Dusk | Codeception |
DB操纵 | Eloquent | SQL, Doctrine |
模板 | Blade | Twig |
数据操纵 | Laravel集合 | 数组 |
表单验证 | Request classes | 他第三方包,甚至在控制器中做验证 |
权限 | Built-in | 他第三方包或者你自己解决 |
API身份验证 | Laravel Passport | 第三方的JWT或者 OAuth 扩展包 |
创建 API | Built-in | Dingo API 或者类似的扩展包 |
创建数据库结构 | Migrations | 直接用 DB 语句创建 |
本土化 | Built-in | 第三方包 |
实时消息队列 | Laravel Echo, Pusher | 使用第三方包或者直接使用WebSockets |
创建测试数据 | Seeder classes, Model Factories, Faker | 手动创建测试数据 |
任务调度 | Laravel Task Scheduler | 脚本和第三方包 |
数据库 | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB |
遵循laravel命名约定
来源 PSR standards.
另外,遵循Laravel社区认可的命名约定:
对象 | 规则 | 更优的写法 | 应避免的写法 |
---|---|---|---|
控制器 | 单数 | ArticleController | |
路由 | 复数 | articles/1 | |
路由命名 | 带点符号的蛇形命名 | users.show_active | |
模型 | 单数 | User | |
hasOne或belongsTo关系 | 单数 | articleComment | |
所有其他关系 | 复数 | articleComments | |
表单 | 复数 | article_comments | |
透视表 | 按字母顺序排列模型 | article_user | |
数据表字段 | 使用蛇形并且不要带表名 | meta_title | |
模型参数 | 蛇形命名 | $model->created_at | |
外键 | 带有_id后缀的单数模型名称 | article_id | |
主键 | - | id | |
迁移 | - | 2017_01_01_000000_create_articles_table | |
方法 | 驼峰命名 | getAll | |
资源控制器 | table | store | |
测试类 | 驼峰命名 | testGuestCannotSeeArticle | |
变量 | 驼峰命名 | $articlesWithAuthor | |
集合 | 描述性的, 复数的 | $activeUsers = User::active()->get() | |
对象 | 描述性的, 单数的 | $activeUser = User::active()->first() | |
配置和语言文件索引 | 蛇形命名 | articles_enabled | |
视图 | 短横线命名 | show-filtered.blade.php | |
配置 | 蛇形命名 | google_calendar.php | |
内容 (interface) | 形容词或名词 | Authenticatable | |
Trait | 使用形容词 | Notifiable |
尽可能使用简短且可读性更好的语法
例子:
1 | $request->session()->get('cart'); |
更优的写法:
1 | session('cart'); |
更多示例:
常规写法 | 更优雅的写法 |
---|---|
Session::get('cart') |
session('cart') |
$request->session()->get('cart') |
session('cart') |
Session::put('cart', $data) |
session(['cart' => $data]) |
$request->input('name'), Request::get('name') |
$request->name, request('name') |
return Redirect::back() |
return back() |
is_null($object->relation) ? null : $object->relation->id |
optional($object->relation)->id |
return view('index')->with('title', $title)->with('client', $client) |
return view('index', compact('title', 'client')) |
$request->has('value') ? $request->value : 'default'; |
$request->get('value', 'default') |
Carbon::now(), Carbon::today() |
now(), today() |
App::make('Class') |
app('Class') |
->where('column', '=', 1) |
->where('column', 1) |
->orderBy('created_at', 'desc') |
->latest() |
->orderBy('age', 'desc') |
->latest('age') |
->orderBy('created_at', 'asc') |
->oldest() |
->select('id', 'name')->get() |
->get(['id', 'name']) |
->first()->name |
->value('name') |
使用IOC容器来创建实例 而不是直接new一个实例
创建新的类会让类之间的更加耦合,使得测试越发复杂。请改用IoC容器或注入来实现。
例子:
1 | $user = new User; |
更优的写法:
1 | public function __construct(User $user) |
避免直接从 .env
文件里获取数据
将数据传递给配置文件,然后使用config()
帮助函数来调用数据
例子:
1 | $apiKey = env('API_KEY'); |
更优的写法:
1 | // config/api.php |
使用标准格式来存储日期,用访问器和修改器来修改日期格式
例子:
1 | {{ Carbon::createFromFormat('Y-d-m H-i', $object->ordered_at)->toDateString() }} |
更优的写法:
1 | // Model |
其他的一些好建议
永远不要在路由文件中放任何的逻辑代码。
尽量不要在Blade模板中写原始 PHP 代码。