本文來自pilishen.com----原文連接; 歡迎來和pilishen一塊兒學習php&Laravel;學習羣:109256050php
該篇屬於《Laravel底層核心技術實戰揭祕》這一課程《laravel底層核心概念解析》這一章的擴展閱讀。考慮到學員們的基礎差別,爲了不視頻當中過於詳細而連篇累牘,故將一些laravel底層實現相關的PHP知識點以文章形式呈現,供你們預習和隨時查閱。laravel
像咱們以前在課程裏提到的,當開發任何正式的laravel項目時,將controller與咱們的Eloquent ORM(或者其餘的數據來源)進行解耦,向來是老練明智之舉。一般咱們會建立一個interface,而後再寫一個實現了這個interface的repository,而後再經過laravel服務容器將對該interface的依賴解析到這個具體的repository上,具體的數據操做咱們都是在repository當中進行。web
一樣的道理也適用於cache。咱們都知道,數據查詢每每是咱們一個web應用裏的主要性能瓶頸,因此不免要爲數據查詢建立相應的緩存(cache)。一樣的,在你的controller裏面具體地實現數據cache,也是很是糟糕的作法——這樣呢,你就將controller與某一種特定的cache實現給強行綁到一塊了,後期若是你想着換一種實現方式,好比從memcache換成redis,那麼你就不得不大量修改你controller裏的邏輯。並且,當某一個數據查詢在多個地方出現時,你就不得不寫重複的cache實現的代碼。redis
或許呢,你能夠在你的repository裏寫cache相關的實現邏輯,對相對較小的項目,這樣倒也行得通。可是呢,這也意味着你的repository就既依賴於ORm,又依賴於你所選擇的cache。這個時候若是你想着更換其中任何一種依賴形式,都極可能意味着你得從新寫一整個新的repository,這期間又要重複不少以前的代碼。緩存
固然,確定有一個更優雅的方式——經過使用「修飾者模式」(decorator pattern),咱們能夠再建立一個repository,讓其實現同一個interface,同時呢,把以前那個repository裏的實現給「包裹」起來,或者說「修飾」一下。在這個cache相關的repository裏,每個方法內都相應調取以前那個數據repository裏的邏輯,而後相應地返回cache事後的response。這樣的話,咱們cache的邏輯,就跟咱們數據操做的邏輯,相對分離開了,假設後期咱們想換一種數據來源,那麼咱們的cache實現也就不會受到影響。bash
假設這是對應於咱們User
model的interface:app
<?php
namespace App\Repositories\Interfaces;
interface UserRepositoryInterface {
public function all();
public function findOrFail($id);
public function create($input);
}
複製代碼
接下來呢是其對應的數據操做的repository:ide
<?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:post
<?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實現「修飾」了一下以前的數據查詢結果。性能
那麼要實際地調用到咱們的這個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實現,好比也能夠在裝飾者中觸發特定事件。