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 App\Api;
- 命名空間。注意,必須限定到MyClass.php所在目錄。即如果MyClass.php放在./src/app/Api/Mobile
下,則namespace App\Api\Mobile
。use PhalApi\Api;
- 要求使用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一下App\Domain下的對應的Domain,然后在需要時new一個domain對象來使用。
Model模型
在Model目錄下新建php類,假設為User.php。通常的開發習慣是,數據庫一張表對應一個Model類,這樣可以實現對表的描述(類似於Mybatis與POJO的配合)。以MySQL為例,注意下列要求:
namespace App\Model;
- 同樣要嚴格限定到User.php目錄use PhalApi\Model\NotORMModel 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 App\Domain\;
- 你懂的- 沒了。
Domain類不要求use框架內部的類,也不要求定義的類繼承相關類。
在User類下寫相關業務函數即可。一般來說,此處函數的參數是Api層請求需要的所有參數。
在業務函數中,調用Model層中封裝好的有關CURD函數,完成業務邏輯。一般來說,需要在User.php頭部use一下App\Model下的對應的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)
要取鹽值,則取法為\PhalApi\DI()->config->get('app.token.SALT')
。
即對於這四大配置文件,均用\PhalApi\DI()->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 \PhalApi\Api;
下行進行注釋,用於說明該類的整體作用 -
在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 \App\Model\Mobile\Other 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
調用方式:\PhalApi\DI()->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 PhalApi\Cache\RedisCache($redis_config);
- 之后,在需要使用Redis的地方利用
\PhalApi\DI()->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目錄
【全文終,謝謝您的閱讀!】