该篇属于[《Laravel底层核心技术实战揭秘》]; 欢迎做客咱们的php&Laravel学习群:109256050(//study.163.com/course/courseMain.htm?courseId=1003575006)这一课程《laravel底层核心概念解析》这一章的扩展阅读。考虑到学员们的基础差别,为了不视频当中过于详细而连篇累牍,故将一些laravel底层实现相关的PHP知识点以文章形式呈现,供你们预习和随时查阅。
原文连接: http://www.pilishen.com/posts...
像咱们以前在课程里提到的,当开发任何正式的laravel项目时,将controller与咱们的Eloquent ORM(或者其余的数据来源)进行解耦,向来是老练明智之举。一般咱们会建立一个interface,而后再写一个实现了这个interface的repository,而后再经过laravel服务容器将对该interface的依赖解析到这个具体的repository上,具体的数据操做咱们都是在repository当中进行。php
一样的道理也适用于cache。咱们都知道,数据查询每每是咱们一个web应用里的主要性能瓶颈,因此不免要为数据查询建立相应的缓存(cache)。一样的,在你的controller里面具体地实现数据cache,也是很是糟糕的作法——这样呢,你就将controller与某一种特定的cache实现给强行绑到一块了,后期若是你想着换一种实现方式,好比从memcache换成redis,那么你就不得不大量修改你controller里的逻辑。并且,当某一个数据查询在多个地方出现时,你就不得不写重复的cache实现的代码。laravel
或许呢,你能够在你的repository里写cache相关的实现逻辑,对相对较小的项目,这样倒也行得通。可是呢,这也意味着你的repository就既依赖于ORm,又依赖于你所选择的cache。这个时候若是你想着更换其中任何一种依赖形式,都极可能意味着你得从新写一整个新的repository,这期间又要重复不少以前的代码。web
固然,确定有一个更优雅的方式——经过使用“修饰者模式”(decorator pattern),咱们能够再建立一个repository,让其实现同一个interface,同时呢,把以前那个repository里的实现给“包裹”起来,或者说“修饰”一下。在这个cache相关的repository里,每个方法内都相应调取以前那个数据repository里的逻辑,而后相应地返回cache事后的response。这样的话,咱们cache的逻辑,就跟咱们数据操做的逻辑,相对分离开了,假设后期咱们想换一种数据来源,那么咱们的cache实现也就不会受到影响。redis
假设这是对应于咱们User
model的interface:缓存
<?php namespace App\Repositories\Interfaces; interface UserRepositoryInterface { public function all(); public function findOrFail($id); public function create($input); }
接下来呢是其对应的数据操做的repository:app
<?php namespace App\Repositories; use App\User; use App\Repositories\Interfaces\UserRepositoryInterface; use Hash; class EloquentUserRepository implements UserRepositoryInterface { private $model; public function __construct(User $model) { $this->model = $model; } public function all() { return $this->model->all(); } public function findOrFail($id) { return $this->model->findOrFail($id); } public function create($input) { $user = new $this->model; $user->email = $input['email']; $user->name = $input['name']; $user->password = Hash::make($input['password']); $user->save(); return $user; } }
咱们能够这样来定义一个cache repository:ide
<?php namespace App\Repositories\Decorators; use App\Repositories\Interfaces\UserRepositoryInterface; use Illuminate\Contracts\Cache\Repository as Cache; class CachingUserRepository implements UserRepositoryInterface { protected $repository; protected $cache; public function __construct(UserRepositoryInterface $repository, Cache $cache) { $this->repository = $repository; $this->cache = $cache; } public function all() { return $this->cache->tags('users')->remember('all', 60, function () { return $this->repository->all(); }); } public function findOrFail($id) { return $this->cache->tags('users')->remember($id, 60, function () use ($id) { return $this->repository->findOrFail($id); }); } public function create($input) { $this->cache->tags('users')->flush(); return $this->repository->create($input); } }
能够看到咱们的这个cache repository里每一个方法,实际上并不负责任何的数据查询操做。咱们经过constructor接收一个一样实现了该interface的具体实现类,也即以前的数据查询的repository,同时接收cache服务,这样呢,咱们不须要触碰任何的数据查询逻辑,直接调取数据相关的repository里相应的方法,而后给它相应地“包裹”上cache便可,或者说用cache实现“修饰”了一下以前的数据查询结果。post
那么要实际地调用到咱们的这个cache实现,咱们还须要更新一下咱们的service provider,好让它把这个“修饰者”,也即咱们的cache repository,给相应地解析出来:性能
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { public function register() { $this->app->singleton('App\Repositories\Interfaces\UserRepositoryInterface', function () { $baseRepo = new \App\Repositories\EloquentUserRepository(new \App\User); $cachingRepo = new \App\Repositories\Decorators\CachingUserRepository($baseRepo, $this->app['cache.store']); return $cachingRepo; }); } }
能够看到咱们实例化了数据查询的repository,也即$baseRepo
,而后实例化cache repository,将数据repository和cache服务传递进去,而后返回这个cache repository的实例。这样了之后,咱们就能够在controller里实际调用了。学习
注意的是,用cache repository来“装饰”本来的数据repository,这只是一个例子、一种用法而已,但愿经过这个,你能学会的是如何“装饰、修饰”你的已有的数据repository,不止是cache实现,好比也能够在装饰者中触发特定事件。