本文所说的Laravel 2018使用数据分析,指的是Laravel Shift的作者Jason McCreary,基于使用Laravel Shift的超过8000个laravel应用所做的分析。(Laravel Shift是一个自动升级你的laravel版本的付费应用,比如你的项目版本是5.1,使用它呢可以自动给你升级到5.6,这期间省去你手动升级的繁琐和烦恼。)

截至到2018年7月,Laravel Shift里有超过8500个上传的laravel apps,每一次版本的升级,Laravel Shift都会生成一个日志文件以用于debug,基于这些日志文件,产生了今天我们提到的laravel使用数据。下面是Laravel Shift里日志文件一瞥:

*** _Shift_ version: 0281cff03fee62f250253f1e485dc7a790209866
*** Cloning app...

>>> _Shift_ 5.2 Event: app did not contain references to SelfHandling
>>> _Shift_ 5.2 Event: could not upgrade middleware Data: ["app\/Http\/Middleware\/Authenticate.php","app\/Http\/Middleware\/EncryptCookies.php","app\/Http\/Middleware\/RedirectIfAuthenticated.php"]
>>> _Shift_ 5.2 Event: could not upgrade app/Providers/RouteServiceProvider.php
>>> _Shift_ 5.2 Event: could not patch app/Providers/RouteServiceProvider.php
>>> _Shift_ 5.2 Event: could not find User model path
>>> _Shift_ 5.2 Event: found additional uses of Event names
>>> _Shift_ 5.2 Event: matched core file: phpunit.xml with version: 5.1.11
>>> _Shift_ 5.2 Event: matched core file: tests/TestCase.php with version: 5.1.33
>>> _Shift_ 5.2 Event: matched core file: database/migrations/2014_10_12_100000_create_password_resets_table.php with version: 5.1.33
>>> _Shift_ 5.2 Event: matched core file: public/.htaccess with version: 5.1.33
>>> _Shift_ 5.2 Event: matched core file: config/broadcasting.php with version: 5.1.11
>>> _Shift_ 5.2 Event: matched core file: config/cache.php with version: 5.1.33
>>> _Shift_ 5.2 Event: matched core file: config/compile.php with version: 5.1.33
>>> _Shift_ 5.2 Event: matched core file: config/database.php with version: 5.1.11
>>> _Shift_ 5.2 Event: matched core file: config/filesystems.php with version: 5.1.33
>>> _Shift_ 5.2 Event: matched core file: config/queue.php with version: 5.1.11
>>> _Shift_ 5.2 Event: matched core file: config/view.php with version: 5.1.33
>>> _Shift_ 5.2 Event: could not upgrade config files Data: {"1":"config\/auth.php","2":"config\/mail.php","3":"config\/services.php","4":"config\/session.php"}
>>> _Shift_ 5.2 Event: could not upgrade package.json
>>> _Shift_ 5.2 Event: app contained phpspec/phpspec requirement of ~2.1
>>> _Shift_ 5.2 Event: found customized namespace

*** _Shift_ ran in: 212.209509

从这些日至里可以看到哪些文件被升级了,用到了哪些功能、哪些组件,等等。

很多apps停留在了5.3,可能因为PHP版本的要求,因为到了5.4测试想转换到Dusk,或者auth组件的变化等。

这应该符合现实情况,因为laravel在5.2~5.3期间一方面做了很多变动,大家要逐步适应和学习,另一方面这些人性化的变动也让laravel更加流行和易用,laravel被大批量地用于生产环境,同时这些变动本身,也逐渐使laravel趋于成熟,满足了大家实际项目的大部分需要。可能没有了特殊的功能需要,大家也就不会那么急迫地更新版本,本身laravel 5.4开始的更新变动也相对小了很多。

当然,也可以说大家的项目还都在“升级的过程中”,取决于升级的时间、人力成本等因素,如果可以的话,可能大家都还想升到laravel 5.5,也即第二个LTS版本。

需要注意的是,接下来的数据样本,laravel 5.5及以上版本的要小一些,同时laravel自身的核心组件,都被排除在外了。

  • 58% of apps use guzzlehttp/guzzle
  • 36% of apps use predis/predis
  • 34% of apps use laravelcollective/html
  • 32% of apps use league/flysystem-aws-s3-v3
  • 27% of apps use intervention/image
  • 25% of apps use maatwebsite/excel
  • 24% of apps use spatie/laravel-backup
  • 23% of apps use laravel/horizon
  • 22% of apps use bugsnag/bugsnag-laravel
  • 21% of apps use laravel/socialite
  • 20% of apps use laravel/passport
  • 19% of apps use sentry/sentry-laravel
  • 15% of apps use spatie/laravel-permission
  • 14% of apps use laravel/scout
  • 14% of apps use league/csv

流行的开发辅助组件:

  • 35% of apps use barryvdh/laravel-debugbar
  • 28% of apps use barryvdh/laravel-ide-helper
  • 19% of apps use laravel/dusk
  • 11% of apps use laravel/browser-kit-testing

编者点评:

  • 值得一提的是,早在两年前(2016年),这里面的一些对于初学者来说比较关键的第三方组件,在我们的Laravel系列课程里也都带领大家使用过了,比如必备的表单组件laravelcollective/html,在我们《Laravel实战:任务管理系统(一)》就跟大家见面了;
  • 处理图片必备的intervention/image,也在我们《Laravel实战:任务管理系统(一)》中大量使用,后来出现了很多其他的图片相关组件,但往往背后也是基于的intervention/image,比如说近来流行的spatie/laravel-medialibrary
  • 项目备份必备的spatie/laravel-backup,是我们在《Laravel&Vue实战:任务管理系统二》一开始就使用的,当时该组件还名不见经传;
  • 关于权限,可以说一开始首屈一指的是Zizaco/entrust,为此呢我们还专门出了免费的公开课《Laravel Entrust角色权限管理》,但是呢entrust的作者突然从去年开始不怎么活跃了,于是santigarcor/laratrust作为entrust的维护版本出现,已经安装了entrust的可以无缝迁移到laratrust上,当然这期间另一个权限组件spatie/laravel-permission凭借其强大的活跃也流行起来了,Laravel也推出了自身的权限功能——Policy。所以权限这块,其实用哪个功能就取决于你自己了,都不错,都可以,那么如果你权限这块感觉有障碍,还是推荐我们的免费的公开课《Laravel Entrust角色权限管理》,了解了原理以后,你可以自行在santigarcor/laratrustspatie/laravel-permission之间选择。
  • 搜索必备组件laravel/scout,这个背后的driver默认基于的是付费服务Algolia,在国内我们更喜欢开源的Elasticsearchlaravel/scoutElasticsearch搭配来开发实时搜索相关的功能,可以看我们的《Laravel & Elastic全文搜索实战》课程。
  • 关于guzzlehttp/guzzle排第一位,可能是因为这两年api开发开始流行,传统上我们经常用guzzle来处理http请求,由于数据来源大部分都是5.3及以下的,这个时候passportaxios还刚开始流行,所以这一点上,可能后期我们会看到passport的排名将攀升,axios因为是前端组件,可能就会被排除在统计数据之外了,但是我们绝不能忽视它的日发流行。

(三)改动最多的文件——config

config文件是改动最多的,虽然这很合理,但是呢改动默认的config文件,也容易导致升级障碍。通常,你可以有其他的方式来处理这些改动,从而使config文件保持默认的样子。

这期间一定记得通过ENV环境变量来改动config文件的值。很多应用喜欢改变config文件当中的默认值,而不是设置ENV,比如假设config/mail.php:

'from' => [
    'address' => env('MAIL_FROM_ADDRESS', 'shift@laravelshift.com'),
    'name' => env('MAIL_FROM_NAME', 'Laravel _Shift_'),
],

这样呢并不好,还是得设置ENV,让config文件保持默认:

'from' => [
    'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
    'name' => env('MAIL_FROM_NAME', 'Example'),
],

当你有很多的配置选项需要设置时,再一种方式就是创建你自己的config文件,比如创建config/system.php, config/settings.php,这样你就不用分别改动多个config文件了。

(四)不推荐自定义的全局namespace

使用默认的APP namespace就好。有9%的apps使用了自定义的namespace,而这个数值应该是0.

如果你更改过namespace,可以这样来改回:

artisan app:name App

当然这并不能改回你在数据库当中,使用到多极对应关系(polymorphic relationships)时的记录,那个你得自己通过sql query来改变了。

编者按: 这个呢,其实在5.3及以下版本,如果通过artisan app:name改变了namespace,实际上是会发生很多莫名bug的,所以不推荐出于好奇随便设置app:name,除非你知道自己在干什么。

(五)apps的目录结构

接下来是在app目录下发现的非laravel官方文件夹:

  • 36% of apps contain app/Models
  • 29% of apps contain app/Services
  • 29% of apps contain app/Helpers
  • 25% of apps contain app/Traits
  • 20% of apps contain app/Rules
  • 18% of apps contain app/Repositories
  • 17% of apps contain app/helpers.php

在laravel 4时代,是默认有app/Models文件夹的,到了5, laravel作者特意将其删掉,因为model这个词在不同的人那里理解不一样,有的人认为一个app的model是其整个的业务逻辑,有的人认为model是一些与关系型数据库进行交互的class,为了不限制大家,干脆删掉,让开发者自己决定该怎么安置model,也即你可以自己创建app/Models文件夹,然后遵循MVC框架的传统方式,也可以“面向业务(service)”,搞一个DDD(Domain-Driven Design)。

当然,这里手动创建 app/Models的,一般都是model数量超过了10个。但是,这里我们想更进一步地,如果model数量超过50个呢?这个时候还是简单地放在 app/Models里,还有特别的意义吗?

app/Services文件夹一般放置一些独立的业务相关的逻辑,可以用来将你的某一部分业务逻辑独立出来,使业务逻辑模块化,甚至方便后期将其独立成为单独的package给其他的项目使用,或者成为一个microservice,关于面向service,或者说package开发,就需要你对laravel底层及其原理有足够的掌握了,这里就推荐我们的《Laravel底层核心技术实战揭秘》

app/Helpersapp/helpers.php应该大同小异,前者放置一些辅助功能的class,后者放置一些全局的helper function,这个在我们的《Laravel&Vue实战:任务管理系统二》中也给大家介绍过了。

app/Rules,这个文件夹严格来说是laravel本身的,因为它是我们执行artisan make:rule后产生的,关于laravel 5.5以后创建自定义的验证规则,也即rule,如果有不懂的同学,可以看我们之前给大家提供的文章:【Laravel 5.5新特性】更方便地创建自定义的数据验证规则Laravel的unique和exists验证规则的优化

关于repository,是否放置在app/Repositories内不是关键,关键是你是否使用,Repository Design Pattern可以说是laravel本身以及其众多第三方组件的命脉之一,Repository Design Pattern对于你分离业务逻辑,或者开发package,也非常关键。repository在laravel刚出来的时候,曾经在国外社区盛极一时,可谓是学laravel必学的,大概在2014年左右可以说是成为一种规范和标准在推行,甚至官方非常简单的起步项目都要介绍和使用,但是呢国内laravel流行的较晚一些,等到国内开始追逐laravel的时候,国外社区都“懒得提”repository了,加上很多国内材料或教程有意无意地躲避repository,说太复杂了不适合新手,没必要让新手学之类的。但其实不是,并不复杂,也并不需要向所谓的新手藏着掖着,否则新手怎么成为高手?

如果你对repository还感到陌生,不知道是咋回事,那么请务必看看我们的《Laravel实战:任务管理系统(一)》,该课程可谓是国内唯一在初学阶段就让你轻松尝鲜Repository Design Pattern的,让你在初学阶段就打下日后成为高手的根基,当然如果你想真真正正掌握Repository Design Pattern的全貌,还是推荐我们的《Laravel底层核心技术实战揭秘》

(六)改造基本的继承关系

这个一般是指自己额外创建一个BaseController 或者 BaseModel class,让它们继承laravel默认的controller或model,然后自己的具体的controller或者model再继承这个BaseController 或者 BaseModel,这期间就可以在BaseController 或者 BaseModel里做一些自己的逻辑。

有23%的应用这么做了,这个呢其实也是不推荐的,这种做法往往在早期的一些国外教程或材料中能看到,但是新近的都不会这么搞,同时这个应该在国内不是很大的问题。

就比如说model,当我们想扩展其功能的时候,更优雅的办法是使用trait,而不是写到BaseModel里,这符合我们编程设计原则里常说的“composition over iinheritance”

(七)Facade的滥用

57%的应用滥用,或者说过度使用facade。Facade本身已然是laravel社区内一个极具争议的话题,或者说是laravel备受非议的一个话题,关于这一点,如果有不了解的,可以看看我们之前给大家写的扩展文章PHP中的facade pattern(外观模式)。那么大部分的apps乱用facade,无异于火上浇油了。最大的争议发生在controllermiddleware当中滥用RequestAuth

比如一起看一下这个controller逻辑:

public function store()
{
    $data = Request::only('product_id', 'token');

    if (Auth::check()) {
        $data['email'] = Auth::user()->email;
    }

    // ...
}

这里呢使用Request来获取请求数据,使用Auth来获取当前用户。但是呢,无论是controller还是middleware,都可以注入一个request实例:

public function store(Request $request)
{
    $data = $request->only('product_id', 'token');

    if ($request->user()) {
        $data['email'] = $request->user()->email;
    }

    // ...
}

这样就不用调用两个facade,而只通过一个request object。关于方法注入、或者依赖注入、或者依赖解析等,无论是我们的初级课程《Laravel实战:任务管理系统(一)》,还是我们的高级课程《Laravel底层核心技术实战揭秘》,都有大量的讲解和使用,这些也是掌握laravel、成为高手的关键。

当然,如果你有真正学习了我们的《Laravel底层核心技术实战揭秘》,或者在阅读PHP中的facade pattern(外观模式)之余做足了功夫,那么你会明白,上面的代码也并不能完全解决facade滥用的问题,因为毕竟Request本身也是一个facade,但是毕竟降低了问题的程度,从而在更好的程序设计和测试过程中,能更大程度地解耦。

(八)View视图中的query查询

24%的应用在view中存在数据查询,这自然是bad practice,视图层不应该直接交互Model,确保使用Controller来传递相关的数据

(九)不要直接调用ENV变量值

42%的应用直接调用ENV变量。Laravel提供了artisan config:cache来提高性能,为了充分利用这一功能,不要直接调用env数据,而是在config文件中调用。因此,你必须得通过config来间接获取env数值

(十)CRUD型Controller

77%的应用还没有采用CRUD型Controller。所谓CRUD型Controller,指的是将controller里的方法限制为默认的CRUD这四类,或者说是默认的resourceful controller,也即里面只有index()create()store()update()edit()show()destroy()这七个方法,任何多出来的方法都可以重构到单独的一个controller,这符合坊间“所有的操作其实归根到底都是CRUD操作”的说法。

当然这一理念呢,还比较新颖,属于是2017年的laravel国际会议laracon上才开始推荐,所以大部分的应用还没有真正地实践,应该国内的开发者也大都对此陌生,不过不要紧,在近期的课程更新中,我们将会在《Laravel底层核心技术实战揭秘》中给大家介绍类似的一些流行做法。

(十一)Controller内的数据验证(Validation)

89%的应用在Controller内进行数据验证,这也是不好的实践——正如我们在入门课程《Laravel实战:任务管理系统(一)》里就讲过的,Controller只是一个“指挥者”,它正常来说不负责任何具体的逻辑,所以此处的数据验证,最好是放到单独的Request文件中,正如我们在入门课程里提倡的那样。

(十二)Blade相关的命令

71%的应用还没有使用Laravel提供的一些blade命令。用的最少,但往往最有用的是@auth@guest@json@method@csrf

当然,这一项所提到的blade命令,其实大都是laravel 5.5才新出的,甚至有些呢文档上也没有提及,所以大家可能还不熟悉。自然,我们在blade里面可以使用原生的PHP标签,但是那样就有可能没有充分利用起来laravel给我们提供的便利与优雅,所以blade当中,我们经常也提倡尽可能地不用原生php标签。

关于blade命令,我们之前也给大家写过两篇文章:【Laravel 5.5新特性】可以在blade中自定义if判断的简略标签Laravel Blade中的@each用法

(十三)额外的一些数据分析

最后呢是一些附加的统计数据,注意的是,该项数据样本相对较小,而且只是限于laravel 5.5及更新版本,该项数据的生成使用的是stefanzweifel/laravel-stats这个组件。

+-------------------+-------+---------+---------------+------------+
| Name              | Usage | Classes | Methods/Class | LoC/Method |
+-------------------+-------+---------+---------------+------------+
| Commands          |   66% |    6.37 |          2.42 |       9.68 |
| Controllers       |   67% |   20.91 |          4.10 |       6.28 |
| Events            |   29% |    5.63 |          1.64 |       7.69 |
| Jobs              |   31% |    4.11 |          2.36 |      11.84 |
| Listeners         |   39% |    5.35 |          1.89 |       5.16 |
| Mails             |   39% |    6.72 |          2.06 |       6.71 |
| Middleware        |  100% |    4.22 |          0.12 |       4.93 |
| Models            |   99% |   17.80 |          3.75 |       3.79 |
| Notifications     |   39% |    4.57 |          3.80 |       3.71 |
| Policies          |   19% |    5.09 |          3.96 |       2.88 |
| Requests          |   58% |   11.04 |          2.07 |       2.52 |
| Resources         |    7% |   14.75 |          0.94 |       4.95 |
| Rules             |   17% |    2.40 |          3.07 |       2.86 |
| Service Providers |  100% |    6.28 |          1.97 |       4.61 |
| PHPUnit Tests     |  100% |    9.96 |          2.02 |       6.63 |
| Dusk Tests        |   18% |       5 |          3.00 |       6.67 |
| Browserkit Tests  |    3% |      13 |          4.16 |       6.05 |
+-------------------+-------+---------+---------------+------------+
| Total             |       |  144.54 |          2.18 |       5.72 |
+-------------------+-------+---------+---------------+------------+
  • 相对来讲,JobsControllerEvents中的每一个method中包含了最多的代码
  • 虽然phpunit test显示的是100%的使用,但实际的情况是,大部分都只是laravel默认自带的示例测试文件。其他的数据显示,只有27%的应用里包含有自定义的测试
  • 可能是laravel-stats这个组件本身的bug,因为显示的是67%的应用使用controller,实际上不可能这么低

结语

看了这些数据,你的laravel学对了吗?用对了吗?希望这些数据能给你的laravel使用与学习,提供更好的参考与建议~

值得自豪的是,通过这些数据,可以看到两年前我们pilishen.com出品的laravel从入门到高手系列课程,两年后的今天,依然可以说是始终保持在laravel规范使用的前列,因此凡是认真学习了我们系列课程的小伙伴,应该也可以自豪地说自己的laravel用得很优雅、没问题,在此祝贺你们,同时感谢一往的支持。

这些数据,是过去的两三年内全球范围内Laravel使用情况的一个缩影,下一个时代,或者说下一个阶段,应该就是Laravel 5.5的时代了。值得庆祝的是,我们的这些系列课程,将于近期统统升级重录,更新到laravel 5.5及更新的版本,以保证小伙伴们继续领先下一个时代,下一个未来的两三年。此次更新,将不只是简单地版本更新,不是简单地把已有项目再做一遍,而是一次系统性的经典升华,升级后的课程将不仅包含本文数据里提到的这些最佳实践与建议,而且将包含大量这些数据里都不曾提到的更优实践,以此来切实保证咱们的小伙伴们真真正正地领先同行。而且,我们已经上车的小伙伴们,将完完全全免费获得更新后的所有课程,不止过去,包括将来,相信你们都是国内laravel开发者中的佼佼者~

到现在还没有上车的小伙伴,你在等什么呢?~