PhalApi 2.7 開發快速上手
- 2020 年 3 月 4 日
- 筆記
PhalApi是一款國人製作的PHP純後端框架。它的開發相當簡單,同時也具備文檔生成等特色功能。下面,我通過簡單的幾點,讓你可以快速入門使用該框架的開發。
建議使用PHPStorm作為IDE,程式碼提示相當完全。由於PHP的熱更新特性,修改過的PHP文件保存後立即生效,無需編譯,無需重啟伺服器。
什麼是PhalApi
PhalApi是一個輕量級的PHP介面框架。有別於傳統的框架,它只面向後端介面的開發。
官網:https://www.phalapi.net
官方文檔:http://docs.phalapi.net/#/v2.0/
安裝PhalApi
Composer是PHP的包管理器(類似於Java的Maven、node的npm)。
Composer的安裝請參考https://pkg.phpcomposer.com/#how-to-install-composer,不要在英文官網直接下載安裝包。
Composer安裝後請立即切換到中國源https://developer.aliyun.com/composer。
Phar是PHP界的Jar包,可以像Jar包一樣引入即用。
在項目目錄下執行composer create-project phalapi/phalapi
即可創建PhalApi項目,項目路徑為./phalapi
。
若需要安裝阿里雲OSS的SDK,則在項目路徑下(注意cd到phalapi目錄)按https://help.aliyun.com/document_detail/85580.html說明調用Composer。
composer require aliyuncs/oss-sdk-php composer install
PhalApi提供了再封裝的PhalApi-OSS阿里雲OSS包(https://github.com/vivlong/phalapi-aliyun-oss),也可以考慮使用
本地調試環境配置
建議使用傻瓜式一體化軟體XAMPP搭建本地的調試環境。
修改XAMPP中Apache的配置文件,找到這兩行:
DocumentRoot "X:/XAMPP/htdocs" <Directory "X:/XAMPP/htdocs">
將引號內目錄修改到PhalApi項目的public目錄,注意使用左斜杠替換右斜杠、
修改後啟動Apache,則項目在localhost:80上啟動。如需修改埠請參考Apache配置文件的其他配置項。
更優雅的介面地址
默認的介面網址為類似於http://xxx.com/?s=App.User.Login(?s後為介面全限定名),不夠美觀。開啟URI路由匹配後可以實現http://xxx.com/User/Login的介面路徑,比較美觀。(App欄位可以省略)
開啟方式:
- 在
./config/sys.php
修改enable_uri_match
配置為true
- 撰寫伺服器Rewrite規則。若使用Nginx伺服器,請直接參考官方文檔示例(http://docs.phalapi.net/#/v2.0/how-to-request?id=開啟uri路由匹配)。
若使用Apache伺服器:- 在
./public
目錄下新建規則文件.htaccess
-
寫入下列內容(即將所有404請求轉發到index.php,作為一個controller)
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php
-
重啟Apache伺服器
- 在
PhalApi的ADM三層模型
有別於軟體開發領域常用的MVC三層模型,在後端純介面開發中,View層顯然沒有任何意義。所以PhalApi採用了創新的ADM三層模型。
- A – Api介面層,只負責接受請求、調度Domain層、發送響應
- D – Domain領域層,最關鍵,負責業務邏輯的處理
- M – Model數據層,只負責與資料庫的交互。注意,它不僅描述Object的基本資訊,還要實現一些與會與資料庫交互的方法。類似於JavaEE中的Bean定義+DAO層
Api介面
三層模型所有的程式碼均在./src/app
目錄下。Api、Domain、Model目錄下默認生成了一些demo,可以刪除。
在Api目錄下新建php類,假設為MyClass.php。注意下列要求:
namespace AppApi;
– 命名空間。注意,必須限定到MyClass.php所在目錄。即如果MyClass.php放在./src/app/Api/Mobile
下,則namespace AppApiMobile
。use PhalApiApi;
– 要求使用Api類。class MyClass extends Api
– 所有類都要繼承自Api類。
在類中定義的一系列public的函數,就是一個個實際的介面(注意,不是類是介面,而是類的成員函數是介面!所以這個類是起到了介面分類的作用)
介面的返回格式永遠是JSON,形式為{ret, data, msg}
,其中ret是HTTP狀態碼,msg是錯誤提示資訊,而data就是我們的業務數據。在函數中return的關聯數組會自動轉化成JSON,注入data。例如
下面介紹介面的調用網址,假設函數名為hello,類文件為MyClass.php
MyClass路徑 | 介面URL |
---|---|
./src/app/Api/MyClass.php | XXX.com/MyClass/hello |
./src/app/Api/Mobile/MyClass.php | (正確)XXX.com/Mobile_MyClass/hello |
./src/app/Api/Mobile/MyClass.php | (錯誤)XXX.com/Mobile/MyClass/hello |
即若類文件在Api目錄下發生了層疊,則需要加入下劃線分隔,而不是一直用斜杠。
下面介紹如何在Api層獲取和處理請求參數。
-
重寫
public function getRules()
方法,public function getRules() { return array( '[FUNCTION NAME]' => array( '[PARAM NAME]' => array('name' => '...', 'require' => ..., 'type' => '...', 'source' => '...', 'desc' => '...', 'min' => ..., 'max' => ...) ); }
返回一個關聯數組,鍵為該Api類下的函數名稱(即介面),值又是一個關聯數組,鍵為參數名,值又是一個關聯數組,用於進行該參數的配置,具體配置項可參考http://docs.phalapi.net/#/v2.0/api-params。下面介紹幾個常用的:
- name:string,前端請求時用的參數名
- require:boolean,是否必須
- type:參數類型,可以用string、int等
- source:string, 參數源,可以用post、get(注意小寫)等
- desc:參數說明,該說明會出現在自動文檔中
- min和max(均可選):當type是int時,可以起到後端參數校驗的作用
-
在介面對應函數的程式碼中取參數:
$param_var = $this->[PARAM NAME]
取好參數,發給Domain層的對應函數,獲取返回值,發送響應給伺服器端。這就是Api層做的事。
一般來說,需要在頭部use一下AppDomain下的對應的Domain,然後在需要時new一個domain對象來使用。
Model模型
在Model目錄下新建php類,假設為User.php。通常的開發習慣是,資料庫一張表對應一個Model類,這樣可以實現對錶的描述(類似於Mybatis與POJO的配合)。以MySQL為例,注意下列要求:
namespace AppModel;
– 同樣要嚴格限定到User.php目錄use PhalApiModelNotORMModel as NotORM;
– 要求使用NotORM類。NotORM是PhalApi內部的封裝的MySQL交互引擎class User extends NotORM
– 模型類必須繼承NotORM-
protected function getTableName($id) { return 'user_score'; }
重寫
protected function getTableName($id)
方法(注意函數簽名帶參$id
),返回值是該模型對應的表名。
現在即可在User類下編寫各個CURD功能的函數,函數參數是進行SQL查詢需要參數。具體使用請參考官方文檔http://docs.phalapi.net/#/v2.0/database-usage。整體風格是鏈式調用,例如:
首先要通過$this->getORM()
獲取NotORM實例,然後組織相關SQL關鍵字即可。
值得一提的是,NotORM的功能非常的強大(起到了SQL語句Builder的作用,極大地避免了直接組織SQL語句),它甚至可以接收關聯數組為參數進行各種智慧的INSERT、UPDATE等操作。具體使用請參考http://docs.phalapi.net/#/v2.0/database-usage,靠這裡的一兩句話是說不清道不明的。
如果有需要,NotORM也支援執行原生SQL語句。
Domain領域
在Domian領域下新建php類,假設為User.php。對於Domain類,要求比較簡單:
namespace AppDomain;
– 你懂的- 沒了。
Domain類不要求use框架內部的類,也不要求定義的類繼承相關類。
在User類下寫相關業務函數即可。一般來說,此處函數的參數是Api層請求需要的所有參數。
在業務函數中,調用Model層中封裝好的有關CURD函數,完成業務邏輯。一般來說,需要在User.php頭部use一下AppModel下的對應的User的model,在進行CURD操作時,new一個model對象來使用。
全局配置文件
在./config
目錄下的app.php、dbs.php、di.php、sys.php就是四大全局配置文件。
如何在./src
中腳本的任意位置取出其中配置的鍵值對?PhalApi用了依賴注入(DI)和反射的功能,實現了看起來非常Java的方式來獲取。
例如在app.php中配置了如下內容:
'token' => array( 'SALT' => 'imsalt', 'expire' => 7200)
要取鹽值,則取法為PhalApiDI()->config->get('app.token.SALT')
。
即對於這四大配置文件,均用PhalApiDI()->config->get
來訪問,參數為配置項的全限定名。
這四大配置文件的作用是:
- app.php – 用戶自定義的相關配置均追加於此
- dbs.php – 資料庫相關配置
- di.php – 依賴注入相關配置,當有新組件插入時需要修改
- sys.php – 系統級配置,例如是否調試、URI匹配等
全局功能函數
如何定義一個在./src
中任何位置都可以調用的功能函數?把這個函數的實現寫在./src/functions.php
中即可。在需要調用時,使用App[FUNCTION NAME]
來調用。
自動介面文檔
不同於Swagger的高侵入性,PhalApi的自動介面文檔系統非常的簡單優雅。不僅方便前端閱讀,還具備自解釋性,利於後續後端的維護。和JavaDoc類似,它全部依靠多行注釋完成。並且,多行注釋內允許使用基本的HTML標籤,如<b></b>
來加粗等等。
注意,合法的多行注釋格式如下,首行有兩個星號。
/** * */
這樣使用:
-
在Api層的每個類文件的
use PhalApiApi;
下行進行注釋,用於說明該類的整體作用 -
在getRules函數內進行的相關參數配置會自動反映到介面文檔中
-
在介面對應函數的正上方進行注釋,用於說明該介面的作用。語法如下:
- 第一行寫介面名稱
@desc
後寫介面描述(description)@return
後寫介面返回值描述,@return [type] [name] [description]
- 如果不想要該介面被自動文檔掃描,則添加
@ignore
若一切配置無誤,則可以在http://xxx.com/docs.php閱讀到自動生成的介面文檔。
介面文檔網頁還可以進行訂製:
- 修改
./public/docs.php
中的$projectName
,可以修改左上角LOGO處的標題。 - 如果需要公共說明(如圖中的統一說明),則在
./public/docs.php
末尾添加php腳本閉標籤(?>
)後,可以書寫HTML程式碼。由於該頁面布局的原因,不建議將公共說明寫在頭部。
前端請求方式
- 對於PHP後端,前端在發送POST請求前必須設置如下請求頭,否則後端收不到數據:
header: {'content-type': "application/x-www-form-urlencoded; charset=UTF-8"}
GET請求沒有類似限制。
-
前端用axios來POST時,data為Object,無需stringify
-
前端收到的響應作res.data後即為如下結構的Object:
{ "ret": 200, "data": { ... }, "msg": "" }
ret為http狀態碼,msg為錯誤提示資訊(當狀態碼非200時才有),data為業務數據
- 在自動介面文檔中,形如App.X_Y.Z的介面請求地址為
http://xxx.com/X_Y/Z
(如果配置了URI匹配)
開發實例
我們以一個簡單的介面為例(獲取表中分數最高的n個記錄),展示一下PhalApi下一個介面的開發過程
- 這是一個公共介面,用於手機端。故在
./src/app/Api/Mobile
下新建PHP類文件Other.php -
進行namespace、use的基本配置,讓Other類繼承Api。編寫類文件注釋用於生成文檔。注意此處use…as…別名的使用。
-
重寫
getRules
方法,接受一個參數n,函數名是getTopN
-
寫
getTopN
函數以及相關文檔注釋。注意,介面函數都不需要參數,而是在內部獲取。
-
開始開發Domain層。在
./src/app/Domain/Mobile
下新建PHP類文件Other.php -
進行namespace的配置,寫業務邏輯程式碼(當n>5時視為n=5處理)。可以看到返回的是一個響應體。所以在Api層是直接return的。注意此處同樣使用了別名
use AppModelMobileOther as ModelOther;
-
顯然該業務需要與資料庫交互,所以需要開發Model層。在
./src/app/Model/Mobile
下新建PHP類文件Other.php -
進行namespace和use配置,Other類繼承NotORM類。重寫
getTableName($id)
方法 -
實現
getTopN($n)
方法。注意,此處SQL查詢的結果會自動轉為關聯數組傳到Domain層,Domain層再向上傳到Api層,Api層響應時關聯數組就自動變成JSON結構注入到響應體的data中了,多麼美妙! -
至此,一個介面開發完成。相應的文檔也已經自動生成了。
系統日誌
PhalApi提供了一個簡單日誌系統。它將日誌等級分類三級:error、info、debug。
保存目錄:./runtime/log
調用方式:PhalApiDI()->logger->error/info/debug([日誌內容], [上下文描述(可選)])
MySQL資料庫
MySQL資料庫需要在./config/dbs.php
內配置。
PhalApi支援實現多庫集群、分庫分表。具體請參考:
- http://docs.phalapi.net/#/v2.0/database-connect
- http://docs.phalapi.net/#/v2.0/database-multi
- http://docs.phalapi.net/#/v2.0/database-other
服務端請求CUrl
如果有需要在伺服器端利用伺服器發送HTTP請求(例如小程式開發中的code2session),PhalApi為我們封裝了CUrl庫來實現,非常簡單。參考http://docs.phalapi.net/#/v2.0/curl。
快取體系
PhalApi支援許多種快取。
此處用常用的Redis說明。
- 在
./config/di.php
中向$di注入Redis依賴:
$redis_config = array('host' => '127.0.0.1', 'port' => 6379); $di->cache = new PhalApiCacheRedisCache($redis_config);
- 之後,在需要使用Redis的地方利用
PhalApiDI()->cache->set/get/delete
等等即可
CORS跨域
利用跨域插件https://github.com/gongshunkai/phalapi-cors,配置相當簡單。
RESTful
由於PHP只是Apache/Nginx上的插件,HTTP服務是由它們提供的,所以若要實現嚴格的RESTful API,必須藉助它們的支援。例如Apache,需要對.htaccess
文件進行配置,來轉發/重定向請求,將RESTful的請求轉化為傳統的。
具體可參考這個實踐:https://www.ctolib.com/luyuanxun-phalapi-restful.html
上線部署
PHP項目的部署非常簡單,上傳程式碼就完事了!將整個phalapi目錄上傳到伺服器上,然後確保你在遠端伺服器上也進行了全文開頭的操作:
- Apache默認文檔路徑指向
./public
- 配置好了Rewrite規則
此刻,你的介面就部署完成了。當然,你應該考慮一下:
- 真實上線,文檔不能讓別人隨意看到!請備份後刪除
./public/docs.php
- 刪除無用的./sdk和./tests目錄
【全文終,謝謝您的閱讀!】