Laravel 5 与 Laravel 4.2 的主要差异和新功能

2015.03.14

以下 L4 指 laravel 4.2 ,L5 指 laravel 5.0

从 2015.2.4 Laravel 5.0 发布到现在已经有一个多月了(其实现在最新版本是 v5.0.16),有的朋友还在使用熟悉的 4.2 ,有的开始探索 5.0 带来的新体验。下面我主要来介绍一下这个 5.0 这个版本与之前 4.2 的差异对比,以及我个人对 L5 使用的一些建议和想法。

建议阅读人群:用 L4 写过程序,看完了 L5 的文档

以下标题都简单的概括了主要特点,对该部分比较熟悉的话可以跳过

更清晰的「目录结构」

旧的 app/models 目录已经完全被移除,但是建议建个新的models目录 app/models 并添加命名空间。而所有的代码都放在 app 目录下,并默认使用 App 这个命名空间。不过默认的命名空间可以使用命令 php artisan app:name Artisan 来批量更改(这里的更改不仅仅是 php 文件中的 namespace ,还有一些程序中包含命名空间的字符串,请不认为通过手动修改文件的 namespace 就能完成全部的命名空间修改)。

控制器( controller ),中间件( middleware ),以及请求( requests ),现在都存放在 app/Http 的对应目录下,因为他们都与应用程序的 HTTP 传输层相关。

新的 app/Providers 目录取代了旧版 Laravel 4.x app/start 里的文件。这些服务提供者有很多启动应用程序相关的方法,像是错误处理,日志记录,路由加载,以及更多。当然,你可以自由的建立新的服务提供者到应用程序。

自定义的一些异常类可以放到 app/Exceptions 中,并在里面的 Handler.php 文件中进行捕获和处理。

自定义的一些事件的话可以放到 app/Events 中。

当然你也可以在 app 文件夹下面添加 ProvidersRepositories 等你需要的文件夹来分类你的程序文件,从而让你的程序目录和逻辑更加清晰。

应用程序的语言文件和视图都移到 resources 目录下。还有你项目的 jscss 文件也建议放到这里,然后通过 Elixir 来处理并自动存储到 public 文件夹下面,供你的项目引用。

虽然繁琐但是更规范的「命名空间」

命名空间这东西确实让很多PHPer「闻风丧胆」的,说的有点夸张,但是确实很多同学不知所措。在L5中,命名空间使用了 PSR-4 的规范,只要按照这个来,就不会有错的。并且免去了 L4 中你曾经一遍又一遍出错,最终发现忘记添加新的类文件后执行 composer dumpautoload 这个命令的烦恼。

model

在命名空间这里专门提到 model 是有原因的。在 L4.2 中由于 app/ 下所有的文件都是没有命名空间也就是在全局的命名空间,所以在使用 Eloquent 的关联的时候你可能这样写 return $this->hasOne('Phone');

但是在 L5 的时候,你需要改为 return $this->hasOne('App\Phone'); 这个样子了。

route

其实 route 这里 url 对应的控制器和方法的字符串也默认是添加了命名空间的,可以在 App\Providers\RouteServiceProvider 这个文件中看到默认的命名空间为 App\Http\Controllers 。但是如果你在 app/Http/Controllers 下面新建的 controller 文件夹来分类你的 controller 的话,在写路由的时候需要添加额外处理一下。例如

Route::controllers([
    'auth' => 'Auth\AuthController',
    'password' => 'Auth\PasswordController',
]);

其他地方需要注意的

由于你的程序都在 App\*** 这样的命名空间下,如果你使用字符串变量作为类名的话,一定把字符串写成完整的带命名空间的类名,否则会报错找不到类的错误。例如

# L4中可能存在的写法
$myClassName = 'Dog';
$obj = new $myClassName(); // 在L5中将要报错

# L5中要修改为
$myClassName = 'app\\Models\\Dog';
$obj = new $myClassName();

性能提高的「路由」

确实在 L5 之前对于100个以上路由的情况很尴尬,效率确实是个问题。在 L5 中,果断添加了缓存来提高效率,对于一些稍微大点的项目来说,收益不小。那就请记住 php artisan route:cache 这个命令。

「中间件」比过滤器更好用

中间件不得不说是个好东西,用过其他语言框架的同学可能会发现这个东西的重要性。中间件能让一个请求在进入你在 route.php 中映射的 controller@method 方法之前,为你做好各种处理。例如处理 HTTP session 的读写,决定应用程序是否处于维护模式,查验跨站请求伪造(CSRF)标记,以及其他更多的功能,包括你自己想像到的在进入controller之前需要处理的一切,并可以实现跳转、报错、记录日志、处理 Request 的内容等。从而保证进入到你的 controller 的请求是如你所愿的。

在 L5 中的使用,你可以简单理解为 L4 的过滤器换成了中间件,但是中间件远比 L4 的过滤器强大并且用处更广了。

「服务提供者」将给你更多帮助

其实服务提供者在 L4 是有使用的,特别是在一些依赖 laravel framework 的扩展包中,不过在我们写程序中使用不怎么广泛。而在 L5 中,更加强调并且提高了这一块的实用性。甚至用新的 app/Providers 目录取代了 L4 的 app/start 里面的文件。这些服务提供者有很多启动应用程序相关的方法,像是错误处理,日志记录,路由加载,以及更多。当然,你可以自由的建立新的服务提供者到应用程序。

简单来说,服务提供者是做一些关于启动应用程序以及注册的事情。还不明白的话,这里有个典型的例子,就是根据环境来加载相应的扩展

// AppServiceProvider.php

public function register()
{
    $this->app->bind(
        'Illuminate\Contracts\Auth\Registrar',
        'App\Services\Registrar'
    );

    if ($this->app->environment('production')) {
        $this->app->register('App\Providers\ProductionErrorHandlerServiceProvider');
    } else {
        $this->app->register('App\Providers\VerboseErrorHandlerServiceProvider');
    }
}

而我们平常写程序中更加广泛的应用就是在 providerregister() 中进行依赖注入的绑定操作,以及 boot() 方法中来进行一些监听事件的绑定。

在 L5 中,对依赖注入更是加强了,让大家用起来更顺手方便了。下面的「上下文绑定」以及「controller的依赖注入」是新的功能。

上下文绑定

在 L4 中,如果你将一个类绑定到一个接口上之后,那么每次根据接口的提示注入的永远是这个类的实现,当你在不同的控制器中想实现 依靠同样的接口注入不同类 的话,那就是不可能的事情了,因为 L4 中只允许一个接口的实现绑定到该接口,除非你放弃把类绑定到接口,直接把注入的类名明确指定,但是这样又违背了依赖注入的灵活性了。

在 L5 中可以根据上下文灵活注入了,例如

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give('App\Services\PubNubEventPusher');

这样你就可以 CreateOrderHandler 中根据提示的接口 EventPusher 来注入 PubNubEventPusher

controller的依赖注入

如果你想在在 L4 中创建一个新上传的视频的时候,想 controllercreate($id) 方法中注入 MoiveCreater 对象的话(举例的 MoiveCreater 这个类包含了视频服务器连接以及创建目录,获取缩略图,视频转换等方法),这是不可能的,因为根据 route 绑定的是一个参数,你不可能写到这个方法里的,解决办法是你注入到 __construct 方法并赋值给类中的变量。

L5 中你可以这样来写,create(MoiveCreater $moveCreater, $id)。这样是不是看起来很酷?哈哈

更多好用的「帮助函数」

由于程序中使用了命名空间,所以你在 controller 中使用一些常用的类操作的话,会不方便,因为会引用很多的类命名空间,例如, \View \Response \Config 等等,或者你在 PHP 文件上面使用 use 来依次引入。

L5 中建议你使用 view() response() config() 等方法来优雅完成你的操作。你想知道所有的这类函数或者实现方法的话,你看这里

能将你的逻辑封装起来的「命令commands」

注意:这里的 commands 和 console command 是两码事啊

相信大家项目中的 controller 随着程序的开发,会有越来越多的输入处理,业务逻辑,输入处理等等,controller 会很庞大臃肿,很影响程序结构的美好以及 laravel 的初衷。

通过 command 对一些业务逻辑进行封装,可以让原来只能在某个 controller 的方法中使用的业务逻辑让其他 controller 进行复用。对 command 的执行可以是同步的也可以是队列形式的。

为安全考虑的「视图模板」

L5 中的 {{ }} 代替了 L4 中的 {{{ }}},而 L5 中的 {!! !!} 这个复杂的写法替换了 L4 中简单的{{ }}。这样的做法很明显,建议大家的输出全部为转义后的安全字符。

简单明了的「配置文件」

在刚接触 L4 的时候,大家可能还在为 L4 的不同环境可以配置不同的配置文件而感动。但是随着时间的推移,我相信不少人通我一样,其实只用一个份配置文件。从而觉的 L4 的配置有些繁琐了。

L5 中的个性配置都在根目录的 .env 文件中了,同时可以拷贝一份作为模板,供其他同事来自行复制修改,这样的操作无疑是最简洁方便的。

为前端考虑集成了Gulp的「Elixir」

如今最流行的前端开发方式就是使用 gulp 来对前端的文件进行合并、压缩、版本控制。在 L5 中这些将更方便,Elixir 可以让你把 js 和 css 等文件存放在 resources 文件夹下面,而通过 gulp 生成的文件将自动发布到 public 文件夹下面。 引用的时候 elixir() 方法会自动处理好在 public 文件夹下的路径是否是添加过版本号的 js 和 css 文件。

最后

上面介绍的是一些我认为常用并且重要的差异以及新功能,当然 L5 中与 L4 的差异远不止这么多,还有更多的细节以及功能,可以参见我的另一篇文章 Laravel 4.2 升级 Laravel 5 全面攻略,里面介绍了一些已经在 L4 中的功能在 L5 中如何实现。

Comments
Write a Comment