我們公司現在在用Laravel
開發項目,同時也增加了Biz
層和Repositories
層,來實現業務邏輯封裝,反而 model
裡面什麼程式碼都沒有。
在Controller
裡寫程式碼的時候,嚐嚐困擾我的問題是如果復用Biz
對象,Repositories
物件和Model
物件。
以前用Yii
開發專案的時候,有一個工廠模式,所以呼叫Model
的時候,基本上都不new
,都是位元組用 XXX::model() 來呼叫的,一個物件被new一次就夠了,能有效節省記憶體。
Controller程式碼:
$productModel = Product::model()->getList('xxxxxxxxx');
多簡單,有沒有?
Laravel
裡,Model
好像沒有工廠,要調用,都需要實例,假如Repositories
裡面封裝了5個方法,每個都使用了Model
,那麼我在Controller
裡呼叫了這5個方法,Model
就被new了5次。
目前在網路上看到一種辦法,就是在Repositories
的建構子裡注入Model對象,放在Repositories的私有成員變數裡,這樣5個方法都會呼叫目前類別的私有變數就可以了。但使用起來就麻煩了,在Controller裡寫程式碼的時候,需要這樣寫:
$xxxBiz = new XXXBiz(\xxx\xxx\Repositories);
在Repositories裡需要這樣寫:
$xxxRepositories = new XXXRepositories(\xxx\xx\xxxModel);
在new一個Biz
的時候,還必須傳入Repositories
對象,而且命名空間還老長,我基本上都是在拼字符串了,寫程式碼效率超低,還要打開這寫文件,去把名字拼出來。
想問大家在用Laravel開發專案的時候,是如何解決Model這種邏輯層類別重複使用的情況?
0x0 前言
有趣的問題,Yii 在業界也是被公認為效能比 Laravel 高的一個框架。於是我想單從 ActiveRecord 的構造,看看兩大框架的具體實作。
0x1 Laravel 的 Eloquent 框架
在 Laravel 中可以輕鬆使用關係查詢:
我在 User 類別裡並沒有找到 find 方法,WTF,發生了什麼事! ?
User 的基底類別是 Model,使用靜態調用,所以會調用 Model 的 __callStatic 魔術方法:
其實就是再呼叫 __call 魔術方法:
追根溯源,我們發現其實 find 方法來自 IlluminateDatabaseEloquentBuilder,而該類別內部使用 IlluminateDatabaseQueryBuilder 的實作。
等等,IlluminateDatabaseEloquentBuilder 和 IlluminateDatabaseQueryBuilder 的差別是啥?
其實 EloquentBuilder 是對 QueryBuilder 的進一步封裝,以便更好的實作關係物件查詢。
那麼,其實過程為:
也就是說,你每次 靜態呼叫 Model 的方法,都會實例化一次 Model,走一次過程。
0x2 Yii 1.1 中的 CActiveRecord
題主既然用到 model 方法,那應該是 1.1 的版本,模組繼承自 CActiveRecord(Yii2 中則繼承自 YiidbActiveRecord)。
好了,夥計們,現在使用 Yii 實現關係查詢,先定義:
查詢:
明顯查詢物件來自 model,看看父類別怎麼實作這個函數:
findAllByPk 方法直接封裝於 CActiveRecord 內部:
所以其過程為:
0x3 使用 Laravel 的依賴注入
通常情況下(無參數的建構子或註入參數已配置),Laravel 會自動幫你實例化:
所以你可以很輕鬆地重複使用同一個物件:
實現完倉庫後,你需要手動實例化嗎:
不,這不符合 Laravel 的哲♂學,你可以這麼簡單:
是的,沒錯,你無需手動構造,傳入 User 實例等等,一切只是一個簡單的自動注入。而且題主注意到這裡使用了命名空間,所以你只需 use 一次。 (當然如果你不想拼寫這麼長的命名空間,那你是時候換一款 IDE 了,PhpStorm 中可以使用 Alt + Enter 快速導入
0x4 最後
對於靜態和非靜態開銷的問題,在 StackOverflow 上有一篇討論:http://stackoverflow.com/questions/14727...
所以說到底還是看業務需求嘛23333
透過依賴注入呀
直接可以注入到Controller中
可以看看這篇文章
http://slides.com/howtomakeaturn/model#/
我假定你對Laravel還不是很了解。
第一,Laravel的Model也就是模型,不需要明確的實例化,呼叫方式像下面這樣(摘自官方文件):
第二,你的描述有錯誤。你尋找的不是工廠模式(factory pattern),而是單例模式(singleton pattern),物件在一次請求生命週期之內,最多只需要實例化一次。在Laravel當中,需要用到IOC(inversion of control)容器或是說是服務容器(service container)。像下面這樣:
以上只是簡單的摘錄,具體用法,請參考Laravel官方優秀的文檔,連結如下:
Service Container(IOC容器/服務容器)
我司是繼承一個BaseRepository,BaseRepository中定義
CouponRepository中
Biz中類似,繼承一個BaseBiz,然後方法這麼寫
Controller中呼叫
Controller ---> Biz ---> Repository
我是這麼做的,在底層 model 裡建立這個函數
修改bootstrap/app.php 和 AppServiceProvider.php
具體參考 Service Provider
在controller 呼叫 Foo::load() 就可以了