为什么我不太想用 Laravel ?
本文首发在我的个人公众号,欢迎关注。
不是不用,是不太想用。
N年前 Laravel 刚面世时,的确让很多人眼前一亮,众人惊呼原来 PHP 代码还可以写得这么简洁优雅。
现在公司有两个项目基于 Laravel5,使用下来总感觉别扭。其实到目前为止,还没有一款真正让我喜欢的框架。曾经年少轻狂,写过框架并用在某教育门户网站,现在看来,还是 too young too simple。从工作到现在,使用、研究过各类流行框架,如Yaf、Yii、CodeIgniter、ThinkPHP、Symfony、Laravel、Slim 、ZendFramework2 等等。
- CI 就不说了,上世纪产品。
- TP 理念陈旧,懒得吐槽。
- ZF2 用过一个实际项目,从此再也不碰了。
- Yii 还行,只是还行。。
- Slim 轻量级,实际用起来略繁琐。
- Symfony 重量级框架,复杂,同时强大。
- Laravel 挺像 Rails,简洁优雅,同时强大。
不得不说,从设计哲学、功能组件、扩展性、社区等各方面来看,Laravel 当之无愧是最火热的PHP框架。
我个人现在主要用 Symfony3,主要是因为熟悉,也有挺多我很喜欢的特性,其它也有很多令人不爽的地方,这个后面单独细讲。
现在主要讲讲 Laravel 让我不爽的地方。
1. 对 IDE 不友好
这一点之所以放第一位,是因为我觉得框架对 IDE 友好直接跟工作效率相关。
说来惭愧,我现在脱离了 IDE(PhpStorm) 基本没法工作了,只能手写很简单的入门级 PHP 代码。反过来说,我个人认为,对 IDE 友好是框架的基本节操,再深挖下去,如果一个框架对 IDE 不友好,能说明什么问题?PhpStorm 堪称宇宙最强PHP IDE,为何就连 Laravel 项目的代码提示都搞不定?加上插件也撇脚?
读过 Laravel 代码后你就会逐步发现,里面用到了很多非常 magic 、tricky、hacky … (词穷了)的代码(或机制)。
下面列出一部分
1.1 首先是容器机制
Laravel 的容器机制的确设计得很灵活,比 Symfony 的 service container 机制灵活强大,但弊端在于对 IDE 不友好,如:$xxx = \App::make('xxx');
这里你能直接知道 $xxx
是什么对象吗?你想调用其下的方法$xxx->someMethod()
时, IDE 不会自动提示,你得翻代码,看文档,找到其 provider 是谁,具体提供了哪个对象,再去看该对象代码。
如默认 helper 里的代码:app('url')->route($name, $parameters, $absolute)
,如果想按住 Command 点击 route
方法,是不能跳转的,IDE 无法识别。
1.2 再来说 Facade
,同样的问题。
Redis::get
这里的方法名不会自动提示,这类常用的简单方法还好,可以直接打出来,对于一些不常用的呢?比如 Redis::ZREMRANGEBYRANK
用之前是不是得查一下 redis 文档看看拼写错了没?虽然运行时大小写不敏感,但建议还是规范写成 Redis::zRemRangeByRank($key, $start, $end);
此时你又得查文档,代码里还找不到,因为这里 Redis 的 provider 提供的实际 instance 是 vendor/laravel/framework/src/Illuminate/Redis/Database.php
,里面用 __call
魔术方法调用 Predis Client。
再如,我在调用某个方法时,通常会先查看其参数有哪些,按住Command,鼠标移到方法名上,就可以显示了,如图:
但是这些 Facade 的静态方法 IDE 通通无法识别,只能继续查文档,翻代码。。
以上部分也就是其 “简洁” “优雅” 的一部分,但 IDE 碰到这些代码就一脸懵逼了,臣妾做不到啊。。。
1.3 Eloquent
通过 Model 查询数据时,我每次都按下面的方式写
\App\Models\User::query()->find(123);
\App\Models\User::query()->where('type', $type)->get();
而不是官方推荐的直接用 where 或 find 等静态方法形式
\App\Models\User::find(123);
\App\Models\User::where('type', $type)->get();
你应该猜到为什么了,因为调用 ->query()
时会返回 Eloquent\Builder
对象,这让 IDE 能够识别,后面的链式调用才能一气呵成。
而静态方法,又是通过魔术方法实现的,IDE 又跪了。
1.4 补丁?
别告诉我要用 laravel-ide-helper
,这个虽然能解决大部分 IDE 兼容问题,但对代码有侵入性,需要加到 composer.json 里,需要启用 provider,需要执行命令生成 meta 文件,这些跟你的项目本身没有半毛钱关系,这么做不觉得跟 Laravel 本身的简洁优雅背道而驰吗? (虽然我现在也加了。。)
总之,对 IDE 不友好,会影响开发者效率,或增加心理负担。
2. Laravel 做得太多
你们别扔鸡蛋。。“特么功能多了也能吐槽?傻x ”
2.1 魔法太多
准确的说这个应该算是优点,只不过。。不知道你们见过下面的姿势没有。。
$user_id = $this->request->get('user_id')
$user_id = $this->request->user_id
$user_id = $this->request['user_id']
我接手的某项目里此类情况挺多,实在是。。
从语义来看,只有第一个是正常的,也是Symfony\Component\HttpFoundation\Request
里提供的默认用法,是调用 request 里 get 方法获取某个参数,而不是读 request
对象的user_id
属性,更不是从request
这个 ”数组(字典)” 里取user_id
这个 key。无力吐槽。
Eloquent Model 对象也是类似,比如
$user = \App\Models\User::find(123);
$user->nickname
$user['nickname']
此类用魔术方法实现的机制有很多很多,可以试试搜索 laravel framework 代码,会发现非常多的 __call
__callStatic
__get
__set
__isset
以此实现的所谓优雅,带来的是语义缺失,写法五花八门。
2.2 自带的 helpers
例如 array_add
array_last
array_sort
…
这些辅助函数的确很有用,不过我自己从来不用,也不推荐。
因为曾有人问我:“这些不是 PHP 默认函数吗?”
好吧。。
以上只是很少一部分,这些严格来说不算是缺点,只是会让程序员更懒、更容易误导、更容易放弃追求本质。特别是对刚入门的程序员。
3. 功能相关
3.1 Facade 机制
前面已经提到一部分,调用某 facade 方法时,你得找到其 provider ,再找到真实 instance 才能看到提供了哪些方法,都有什么参数等等。
绕了一圈,才能找到真实出处,这点有些反直觉。
另外,如果你想自定义 facade ,你得写一个 facade 模板文件,在 getFacadeAccessor
里返回一个唯一标识(取名),然后在某 provider 里注册一下,然后再加到配置文件的 aliases 中。
你会发现其实 facade 模板文件非常鸡肋,除了定义标识以外基本没卵用。
不过, Laravel5.4 版里已经优化成 real-time facade
, 本质是说 “噢,facade 模板文件的确很鸡肋,现在我可以帮你自动生成~ 标识就是类名~”
在找不到某个 facade 模板文件时帮你自动生成一个缓存文件,命名空间是 Facades\<your namespace>
,此处仍然很 magic
如,以 App\MagicFacade
为例
namespace App;
class MagicFacade
{
public function hello() {
return ’hello laravel’;
}
}
然后
此时 PhpStorm 先懵逼一会。。
magic 之处在于,将某个类当做 facade 时,在其命名空间前加上 Facades\
就可以了,现在你告诉我 Facades\App\MagicFacade
对应的方法文件是 App\MagicFacade
,其实生成的 cache 文件才是亲儿子。。
这难道不也是反直觉吗?语义呢?
3.2 Blade 模板
足够简单,但不够纯粹,感觉就是在写 PHP 代码,除了关键词替换了以外。如 $users as $user
$loop->first
等等
@foreach($users as $user)
@if ($loop->first)
This is the first iteration.
@endif
@endforeach
最不可思议的是,居然可以在模板里写 PHP 代码?
[@php](https://learnku.com/users/10050)
//wtf ?
@endphp
“权限”太大,以至于,还可以有这种操作?
@foreach(User::where('type', $type)->get() as $user)
{{ $user->name }}
@endforeach
当然,这也是开发规范问题。
不过我更喜欢 Twig 模板引擎,足够灵活,且职责明确。
4. 其它
以下这些问题其它框架也都存在,不是吐槽,只是个人喜好
4.1 路由定义
Laravel 的路由定义跟 Rails 很相似,不过我更喜欢 Symfony 里的写法:
用注释形式定义好路由信息就可以了,还顺带能自动生成API文档:
Laravel 从 5.0 开始去掉了类似功能,现在你可以通过第三方包 LaravelCollective/annotations
实现此功能。
4.2 数据表维护
项目快速迭代期间,数据表变动是很常见的,难道每次变动都写一个 migration 文件?虽然 Laravel 的 migration 很好用,堪比 Rails ,但我更喜欢 Symfony + Doctrine 的用法,在 Entity 文件(类似 Laravel 里的 Model 文件)里以注释形式定义各个字段属性:
通过 doctrine:schema:update
命令可以自动更新数据库到最新状态,其会比对当前 Entity 属性与数据库的差异,生成对应的SQL语句并执行更新。
这个跟 Laravel 的 Schema change 方法类似,底层都用到了 doctrine/dbal
组件。Laravel 里也可以通过 laraveldoctrine
项目实现类似功能。
5. 最后
整体觉得 Laravel 虽然强大,但很多特性是牺牲了语义化,或是反直觉的。当然,这些并不阻碍其成为 PHP 社区最火框架。
Laravel 跟 Rails 很像,Rails 社区哲学是约定优于配置
, Laravel 也是类似,以上问题本质上不是什么大问题,按照社区约定做法还是挺不错的。
我现在常用的 Symfony3 ,本身也有很多槽点,下期再讲。
好了,以上是我的个人喜好,大家可以扔鸡蛋了。
求关注
最近才开始写公众号,求关注~
也可以加我的个人微信号:henter
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: