原文地址:https://prinzeugen.net/optimi...php
這篇文章應該算是心得體會一類的吧,由於並無什麼卵用(笑laravel
就像前兩篇文章說的同樣,在我把項目框架改成 Laravel 後,天然要最大限度地利用 Laravel 的特性來提高咱們應用的性能(雖然使用 Laravel 自己就是在下降性能了),而且讓咱們的代碼看起來更優雅 裝逼。數據庫
其中咱們能夠最方便地利用的一個特性就是 Laravel 的服務容器了。在這裏我很少贅述 Service Container 是個啥,想了解的能夠自行搜索。不想了解的就只要大體知道它是個能夠 綁定/取出 實例的東西就行了(固然服務容器可不止這麼點功能)。數組
相信不少 Web 應用都會在數據庫創建一個 options
表來儲存一些用戶的配置信息,而爲了方便,咱們一般會封裝一個 Option
類來方便地進行數據的 get
、set
操做。而一般的作法是把這些操做作成類內靜態方法來調用。app
可是這樣的弊端就是每一次的操做都要去查詢數據庫,這對於性能仍是有挺大影響的,尤爲是在一次響應中要使用不少 options 的狀況下。框架
那麼在 Laravel 下咱們能夠怎麼優化呢?ide
蛤?你說 Eloquent?你 TM 長點腦子啊 用了 ORM 那 tm 還叫優化?大家呀,不要聽的風是得雨,看到 Laravel 就想到 Eloquent!函數
好吧好吧,再強行 +1s 是要出事的,咱們回到正題。沒錯,咱們正是要把 options
放到 Laravel 的服務容器裏去。性能
這樣的話咱們只須要在應用啓動的時候實例化一個 OptionRepository
類,在構造函數裏讀入全部的 options
並放到類內屬性上,get
方法直接從該屬性裏取值,而調用 set
操做的時候則對該屬性進行修改,同時 push 修改過的 key
到一個 $items_modified
數組裏去,在對象析構的時候再真正執行數據庫操做,寫入全部修改過的 options
。優化
下面咱們來定義 OptionRepository
類:
<?php namespace App\Services; use DB; use ArrayAccess; use Illuminate\Support\Arr; use Illuminate\Contracts\Config\Repository as ConfigContract; class OptionRepository implements ArrayAccess, ConfigContract { /** * All of the option items. * * @var array */ protected $items = []; protected $items_modified = []; /** * Create a new option repository. * * @return void */ public function __construct() { $options = DB::table('options')->get(); foreach ($options as $option) { $this->items[$option->option_name] = $option->option_value; } } /** * Determine if the given option value exists. * * @param string $key * @return bool */ public function has($key) { return Arr::has($this->items, $key); } /** * Get the specified option value. * * @param string $key * @param mixed $default * @return mixed */ public function get($key, $default = null) { return Arr::get($this->items, $key, $default); } /** * Set a given option value. * * @param array|string $key * @param mixed $value * @return void */ public function set($key, $value = null) { if (is_array($key)) { foreach ($key as $innerKey => $innerValue) { Arr::set($this->items, $innerKey, $innerValue); $this->items_modified[] = $innerKey; } } else { Arr::set($this->items, $key, $value); $this->items_modified[] = $key; } } protected function save() { $this->items_modified = array_unique($this->items_modified); foreach ($this->items_modified as $key) { if (!DB::table('options')->where('option_name', $key)->first()) { DB::table('options') ->insert(['option_name' => $key, 'option_value' => $this[$key]]); } else { DB::table('options') ->where('option_name', $key) ->update(['option_value' => $this[$key]]); } } } /** * Prepend a value onto an array option value. * * @param string $key * @param mixed $value * @return void */ public function prepend($key, $value) { $array = $this->get($key); array_unshift($array, $value); $this->set($key, $array); } /** * Push a value onto an array option value. * * @param string $key * @param mixed $value * @return void */ public function push($key, $value) { $array = $this->get($key); $array[] = $value; $this->set($key, $array); } /** * Get all of the option items for the application. * * @return array */ public function all() { return $this->items; } /** * Determine if the given option option exists. * * @param string $key * @return bool */ public function offsetExists($key) { return $this->has($key); } /** * Get a option option. * * @param string $key * @return mixed */ public function offsetGet($key) { return $this->get($key); } /** * Set a option option. * * @param string $key * @param mixed $value * @return void */ public function offsetSet($key, $value) { $this->set($key, $value); } /** * Unset a option option. * * @param string $key * @return void */ public function offsetUnset($key) { $this->set($key, null); } /** * Save all modified options into database */ public function __destruct() { $this->save(); } }
能夠看到咱們順便實現了 ArrayAccess
接口,因此咱們在拿到 OptionRepository
的實例後就可使用相似於 $option['fuck']
的形式來獲取數據了(其實我後來一次也沒用到)。
不過光是實現了一個 Repository
仍是不夠的,咱們還須要把它綁定到服務容器裏,同時註冊個 Facade
給它,讓咱們可以更優雅地調用倉庫類的相關方法:
class AppServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { // 綁定單例到服務容器上 $this->app->singleton('option', \App\Services\OptionRepository::class); } }
新建一個 Option
類並集成 Laravel 的 Facade
基類:
<?php namespace App\Services\Facades; use \Illuminate\Support\Facades\Facade; class Option extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'option'; } }
而後咱們在 config/app.php
中加入咱們 Facade 的別名:
<?php return [ 'aliases' => [ 'Option' => App\Services\Facades\Option::class ], ];
大功告成!咱們如今又能夠像之前那樣方便地使用相似於 Option::get('shit')
的方法獲取數據,並且又大幅減小了數據庫操做,是否是很棒呢~ (=゚ω゚)=
好吧其實本文也沒講啥有用的東西,不過但願對從其餘框架遷移到 Laravel 的開發者們有所啓示~