一個微型的PHP實現的AR庫
體積很小帶詳盡的注釋總共只有400行
支援鏈式調用
支援關係
前言
最開始接觸ActiveRecord是在學習Yii的時候,那個時候覺得用AR操作資料庫真的是太方便了。以至於後來轉向其他的一些架構的時候,感覺沒有了AR似乎就不能操作資料庫了一樣!!!特別是中間自己使用一些簡單的說不上架構的東西來寫微型的PHP網站的時候,感覺手寫SQL太難看。
後來也接觸過一些優秀的獨立的ORM的庫,比如我最喜歡的idiorm. 甚至曾經萌生了想要把Yii的AR單獨拿出來用的想法!但是後來還是沒有實現。。。
在13年的時候,有一段時間上班時間太清閑,所以當時就想自己實現一個ActiveRecord類,一來打算練練手,而來也打算自己以後用的上。
準備
在開始動手寫之前,在github,以及stackoverflow上面尋找了一大堆的php的AR庫或者ORM的庫。
https://github.com/j4mie/idiorm
https://github.com/vrana/notorm
https://github.com/PrimalPHP/Record
https://github.com/spadgos/Record
https://github.com/sgoen/php.pdo.orm
https://github.com/jaceju/example-my-orm
當然其中最好的就是idiorm以及notorm,在github上門分別有1600+和600+的star。
拿idiorm來說,個人非常喜歡它提供的介面以及使用方式。而且整個庫也就單個檔案,雖然檔案將近2500行。但是已經算是一個小型的庫了。當然檔案有點長,看起來有點費勁。
相對而言notorm設計得更加OO一些。不過在其中的NotORM_Result這個class中明顯看到一大片字串拼接SQL的方式,還是讓人覺得看起來不是很好。
設計
在看了一堆這樣的ORM的庫之後,非常反感那種直接拼接SQL的方式,但是這又是一個無法避開的問題,最後總是需要產生一個SQL字串的。
關鍵在於需要找出一種比較”優雅“的方式來完成這個拼接的工作。
運算式
有一天在看拼接的SQL的時候偶然間感覺SQL裡面where後面的那些查詢條件總是一個一個的運算式(一個運算元加上一個操作符再加上一個運算元,例如:name='demo' and email='demo@demo.com')。
這個運算式的結構看起來和數學裡面的(1+1)*(2+2)是那麼的相像。
甚至連and,or也是一個一個的操作符而已。再提煉一下除了二元運算式,還有一元運算式(只有一個運算元的運算式,類似數學裡面的-1)。這樣算起來SQL裡面的select,from,where,delete,update這樣的關鍵詞都可以算成是”操作符“了。
那麼一個簡單的SQL就可以分解成一個一個的運算式:
select email, password from `user` where email = 'demo@demo.com';
select email, password
from user
where email = 'demo@demo.com'
email = 'demo@demo.com'
上面的SQL總共拆分出來了4個運算式,其中where部分是嵌套的一個運算式。
實現
Expressions
所以,我專門定義了一個Expressions類用來表示SQL中的各個部分。這個類只有一個__toString方法在最後需要的時候產生SQL
class Expressions extends Base { public function __toString() { return $this->source. ' '. $this->operator. ' '. $this->target; }}
當然還有比較特殊的運算式就是"()",這個運算式特殊在於操作符是分開的。
介面
當提煉出來了運算式的類之後,那麼在使用ActiveRecord查詢資料庫的時候,每輸入一個動詞,都只是在適當的地方插入一個運算式而已。只有在最後的時候才會一次性的調用每一個運算式的__toString方法組合SQL,為了安全考慮,使用了PDO的綁定參數的形式防止SQL注入的風險!
比如:
$user->equal('id', 1);只是在where子句裡面產生了一個 "id=:ph1"的運算式,同時儲存了一個array(':ph1'=>1)的參數而已。同樣的還提供了簡寫的”eq“以及”ne“,”ge“等介面函數。另外還有”select“,”from“,”group“,”order“,”limit“,”top“以及”where“等介面函數。
魔術方法
為了減少代碼量,所以這裡使用了__call魔術方法避免了為每一個動作都去定義個method。
關係
除了實現SQL的基本操作,還實現了一下類似Yii的ActiveRecord法讓Relation的方法可以簡單的通過主外鍵關係查詢資料。
定義了”HAS_ONE“,”HAS_MANY“和”BELONGS_TO“三種關係。
可以在定義關係之後,能通過簡單的的訪問屬性的方式獲得關聯的資料。
項目
項目地址:https://github.com/lloydzhou/activerecord
文檔地址:https://lloydzhou.github.io/activerecord
已經提交到packagist.org可以通過composer安裝
composer require lloydzhou/activerecord
DEMO
為了一邊測試,一邊完善這個庫。所以使用這個庫結合另外一個Router和 MicroTpl 寫了一個簡單的 部落格 ,裡面基本涵蓋了這幾個庫的API。