該篇屬於[《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實現,好比也能夠在裝飾者中觸發特定事件。