成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PHP后端組織項(xiàng)目結(jié)構(gòu)的思考

cikenerd / 951人閱讀

摘要:介紹下一個(gè)新項(xiàng)目,后端該如何從零去搭建。我們先假設(shè)這個(gè)項(xiàng)目由兩部組成提供給站點(diǎn)使用的提供給運(yùn)營(yíng)人員使用的管理后臺(tái)。因此通過回顧,我們得出我們的后端項(xiàng)目需要一個(gè)的層次,來(lái)存放業(yè)務(wù)邏輯。

這是 后端開發(fā)者從零做一個(gè)移動(dòng)應(yīng)用 的后端部分第二篇。介紹下一個(gè)新項(xiàng)目,后端該如何從零去搭建。我們先假設(shè)這個(gè)項(xiàng)目由兩部組成

提供給wap站點(diǎn)、app使用的api;

提供給運(yùn)營(yíng)人員使用的管理后臺(tái)。

整個(gè)項(xiàng)目采用 Phalcon,項(xiàng)目的demo可以 點(diǎn)這里 參閱

備注:跟隨文章進(jìn)度,項(xiàng)目持續(xù)更新,最后會(huì)與配套的wap app形成一個(gè)整體

項(xiàng)目最終至少會(huì)包含以下內(nèi)容:

小米消息推送

支付集成(支付寶、招商、微信)

基于 Codeception 的api測(cè)試

登陸api(這部分采用oauth2,會(huì)基于 "bshaffer/oauth2-server-php" 做)

項(xiàng)目結(jié)構(gòu)回顧

后端系統(tǒng)一般都是采用 MVC 結(jié)構(gòu)(這里均以PHP為例),M 代表模型,V 代表視圖,C 代表控制器。我在啰嗦幾句

Model指的是數(shù)據(jù)模型,這個(gè)數(shù)據(jù)模型包括你的Mysql中的表結(jié)構(gòu),或者redis的緩存對(duì)象結(jié)構(gòu)都可以。它代表一個(gè)數(shù)據(jù)操作單元。

View指的展示給用戶瀏覽、直接操作的界面,這個(gè)大家都懂,不多說

Controller 控制器,主要是為了隔離 View 與 Model 直接打交道,他做為一個(gè)中間人,兩頭傳遞小紙條。

在我過往的項(xiàng)目中,我主要的困惑在于,業(yè)務(wù)邏輯是放在 C 還是放在 M。

從對(duì)象角度出發(fā),業(yè)務(wù)邏輯無(wú)非就是操作數(shù)據(jù),要么讀取,要么修改,那么應(yīng)該放在M層,因?yàn)橐粋€(gè)對(duì)象應(yīng)該有自己的屬性與方法。

業(yè)務(wù)放在M中

實(shí)際工作中我們常常有這樣的場(chǎng)景,比如:讀取一個(gè)游戲列表數(shù)據(jù),數(shù)據(jù)包括游戲的詳情以及游戲的版本信息以及下載信息。因?yàn)橛螒騛pp會(huì)存在升級(jí),因此一個(gè)游戲會(huì)對(duì)應(yīng)多個(gè)包。那么這里至少存在兩個(gè)model

游戲詳情model,包括游戲的名稱,logo等基本信息

游戲的包信息model,包括包所屬平臺(tái),大小,下載地址,版本信息等

那么這個(gè)動(dòng)作的方法應(yīng)該封裝在哪里呢?以前的做法是,分別封裝對(duì)應(yīng)的操作到對(duì)應(yīng)的model,然后在控制器中分別調(diào)用。說回到這里,游戲model封裝了查詢游戲列表的method,然后包model封裝了根據(jù)游戲id查詢包信息的method。

然后我們?cè)诳刂破髦蟹謩e調(diào)用這個(gè)兩個(gè)方法,然后再進(jìn)行組裝,把游戲?qū)?yīng)的包設(shè)置到對(duì)應(yīng)的游戲中。

那么有一個(gè)問題,假設(shè)我們?cè)谟螒蛟斍檫@個(gè)控制器方法中,需要返回一個(gè)相關(guān)游戲的集合,難道又重復(fù)一次上面的操作?
有人會(huì)說把處理游戲部分抽離成一個(gè)公共方法,那么假設(shè)是要在新聞詳情里邊調(diào)用呢?這根本不該在同一個(gè)控制器里邊??!

業(yè)務(wù)放在C中

上面我們把方法放在model中遇到了復(fù)用的小麻煩,那么繼續(xù)看看放到controller中會(huì)怎樣?

這個(gè)時(shí)候的一個(gè)好處是:我們可以使用連接查詢,將剛剛的2次查詢,通過連接查詢1次完成,對(duì)于mysql的時(shí)間減少了,程序性能提升,然后對(duì)查詢結(jié)果啪啪啪處理完成。

好吧,不往后面說了,相信大家已經(jīng)發(fā)現(xiàn)了,這個(gè)查詢過程還是不可復(fù)用。自然而然的,我們這里應(yīng)該想到,將它提煉成一個(gè)方法,無(wú)法滿足其他控制器使用(一個(gè)控制器調(diào)用另外一個(gè)控制器的想法想都別想?。D敲粗荒芴釤挸梢粋€(gè)類了,這個(gè)類來(lái)封裝所有的業(yè)務(wù)。

這樣之后,任何需要游戲列表數(shù)據(jù)的地方,直接調(diào)用這個(gè)GameServer(假設(shè)封裝的業(yè)務(wù)邏輯都放在xxxServer中)就可以獲得相同的數(shù)據(jù),然后如果業(yè)務(wù)變動(dòng),我們也只需要改動(dòng)這一處,所有地方得到的數(shù)據(jù)也將會(huì)是一致的。

因此通過回顧,我們得出我們的后端項(xiàng)目需要一個(gè)server的層次,來(lái)存放業(yè)務(wù)邏輯。

Server層存在的意義

分離出來(lái)的這一層,集中涵蓋了所有的業(yè)務(wù)功能,極大的提高了代碼的復(fù)用性,除了不同控制器不同方法的直接使用,還包括了不同模塊之間的復(fù)用。

但是在不同模塊之前服用,server層也需要考慮一些額外的東西,比如我們有一個(gè)app api模塊,有一個(gè)后臺(tái)管理模塊。那么都是獲取列表數(shù)據(jù),可能給app api模塊可能不需要某些字段,但是后臺(tái)管理需要知悉全部?jī)?nèi)容,以及后臺(tái)用戶權(quán)限上的一些問題。這些部分可以繼續(xù)進(jìn)行拆分,與server組合。需要結(jié)合自己的業(yè)務(wù)來(lái)進(jìn)行管理。

我個(gè)人實(shí)踐過程中代碼的另外一個(gè)好處是,server層從某種層度上讓C層變得簡(jiǎn)單,這讓團(tuán)隊(duì)中的新人能夠快速上手接觸代碼。比如小明是團(tuán)隊(duì)新人,那么在他熟悉所使用框架的前提下,他可以立刻在C層開始做事情,因?yàn)檫@里沒有業(yè)務(wù),有的只是驗(yàn)證客戶端傳過來(lái)的數(shù)據(jù),以及對(duì)server層的調(diào)用返回。通過這個(gè)過程可以加速其融入團(tuán)隊(duì)的進(jìn)程。

統(tǒng)一的返回格式

約定api返回的數(shù)據(jù)格式,這基本上是系統(tǒng)開發(fā)開始的第一步,原先常用的方式就是在每個(gè)控制器中通過

return json_encode([
    "msg" => "ok",// 攜帶的信息,可以用來(lái)前端 alert 提示用戶
    "data" => [// 具體數(shù)據(jù)
        ... ...
    ],
    "code" => "0", // 0表示成功,其他表示對(duì)應(yīng)錯(cuò)誤
])

那么這里首先遇到的第一個(gè)問題,為了簡(jiǎn)化前端對(duì)類型的判斷,基本上所有的字段值,都是返回字符串形式。那么 data 里邊的內(nèi)容就需要在每個(gè)控制器中進(jìn)行處理字符串、utf-8編碼等問題。要重復(fù)代碼,就算你抽離成一個(gè)方法,也需要面對(duì)該問題。好點(diǎn)的解決方案是在返回?cái)?shù)據(jù)的攔截器(每一個(gè)框架都有類似的概念)內(nèi)進(jìn)行統(tǒng)一的處理。

像上面這樣的代碼寫法,帶來(lái)的額外問題可能有,字段名稱打錯(cuò),比如: code 寫成 cdoe ,data 寫成 date。為程序代碼額外的風(fēng)險(xiǎn)(尤其是bug修復(fù)時(shí)最容易出現(xiàn)該情況)

那么一種解決辦法就該由此想到,采用對(duì)象的方式來(lái)規(guī)范化返回的數(shù)據(jù)結(jié)構(gòu)。比如我們定義一個(gè)類:

class ResultData {
    
    /**
     * 返回的信息提示
     * @var string $msg
     */
    private $msg;

    /**
     * 返回的數(shù)據(jù)結(jié)構(gòu)
     * @var array|object|string
     */
    private $data;
    
    /**
     * api 狀態(tài)碼
     * @var int $apiCode
     * @see ApiCode
     */
    private $apiCode;
    
    public function __construct(int $apiCode, string $msg = "ok", $data = null)
    {
        $this->apiCode = strval($apiCode);
        $this->msg = trim(strval($msg));
        $this->data = $data;
    }
    
    /**
     * 獲取數(shù)據(jù)結(jié)果
     * @return array
     */
    public function getRetData()
    {
        if (! is_array($this->data) && is_object($this->data) && method_exists($this->data, "toArray")) {
            $this->data = $this->data->toArray();
        }

        // valueToString 將data的value轉(zhuǎn)化為 string 并且做utf-8轉(zhuǎn)碼
        $result = [
            "code" => $this->apiCode,
            "msg" => $this->msg,
            "data" => $this->data ? ArrayUtil::valueToString($this->data) : [],
        ];

        if (! APP_ENV_PROD) {// 測(cè)試環(huán)境顯示 api 的處理時(shí)間信息 方便優(yōu)化
            $result["use_time"] = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
        }

        return $result;
    }
}

有了上面這個(gè)類,我們所有的服務(wù)層或者controller都應(yīng)該用它作為返回值。然后在攔截器中統(tǒng)一進(jìn)行json encode即可。這樣子即減少了犯錯(cuò)的可能性,同時(shí)對(duì)統(tǒng)一處理數(shù)據(jù)的地方做了統(tǒng)一管理集中到 ResultData 中,那么以后有什么特殊變動(dòng),調(diào)整一處,處處生效。

其它問題

另外還有關(guān)于 oauth2 如何集成到項(xiàng)目中等等問題,這部分均放到 x-api 項(xiàng)目中進(jìn)行說明,紙上說來(lái)終覺淺嘛。

日志的記錄也是系統(tǒng)開發(fā)非常重要的部分,這部分沒什么太多說的,用規(guī)范的格式,存儲(chǔ)指定的數(shù)據(jù)(介質(zhì)可以是:db、file)。

系統(tǒng)開發(fā)中應(yīng)該拒絕使用 var_dump、echo 這些方式進(jìn)行調(diào)試,另外建議采用:PhpStorm IDE來(lái)進(jìn)行系統(tǒng)開發(fā)。

后續(xù)分享

接下來(lái)會(huì)完善一個(gè) x-api 的基本結(jié)構(gòu),以及php自動(dòng)化測(cè)試部分文檔教程,然后后端部分就告一段落。(本系列的分享主要集中在代碼層面,不涉及相關(guān)系統(tǒng)部署問題)


GitHub:https://github.com/helei112g

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/25613.html

相關(guān)文章

  • 后端開發(fā)者從零做一個(gè)移動(dòng)應(yīng)用(后端篇)

    摘要:后端開發(fā)的疑惑后端開發(fā)最常面對(duì)的一個(gè)問題性能高并發(fā)等等。而到了時(shí)代,在方面有了前后端分離概念移動(dòng)后端更是無(wú)力渲染天然前后端分離。 先來(lái)上一張前端頁(yè)面的效果圖(Vue + Vux + Vuex + Vue-Router)。showImg(https://segmentfault.com/img/remote/1460000010207850); 第一次做gif 沒什么經(jīng)驗(yàn),太大了。加載...

    codergarden 評(píng)論0 收藏0
  • PHP 進(jìn)階之路 - 后端多元化之快速切入 Java 開發(fā)

    摘要:以實(shí)現(xiàn)自己熟悉的東西為導(dǎo)向比如我們做后端開發(fā),首先是常用的循環(huán)迭代條件判斷增刪改成。它是由實(shí)現(xiàn)的,不保證元素的順序,也就是說所說元素插入的順序與輸出的順序不一致。 下面是我直播的文字版,直播地址:https://segmentfault.com/l/15...代碼:https://github.com/zhoumengka...整個(gè)項(xiàng)目我們我又細(xì)分了6個(gè)版本來(lái)演進(jìn),希望更加便于大家對(duì)比...

    Cristic 評(píng)論0 收藏0
  • PHP 進(jìn)階之路 - 后端多元化之快速切入 Java 開發(fā)

    摘要:以實(shí)現(xiàn)自己熟悉的東西為導(dǎo)向比如我們做后端開發(fā),首先是常用的循環(huán)迭代條件判斷增刪改成。它是由實(shí)現(xiàn)的,不保證元素的順序,也就是說所說元素插入的順序與輸出的順序不一致。 下面是我直播的文字版,直播地址:https://segmentfault.com/l/15...代碼:https://github.com/zhoumengka...整個(gè)項(xiàng)目我們我又細(xì)分了6個(gè)版本來(lái)演進(jìn),希望更加便于大家對(duì)比...

    xi4oh4o 評(píng)論0 收藏0
  • PHP中static與yield關(guān)鍵字思考

    摘要:先來(lái)說說關(guān)鍵字。什么時(shí)候用來(lái)修飾方法關(guān)鍵字大家都知道是用來(lái)修飾方法與屬性的。一句話學(xué)會(huì)面向?qū)ο蟮姆绞絹?lái)思考。充分發(fā)揮其性能優(yōu)勢(shì),又能解決擴(kuò)展性差的問題。這里不會(huì)進(jìn)行與的比較。 你以為你知道了一切,只是你以為而已。知識(shí)的美妙就在于,一生的時(shí)光在它面前顯得多么的短暫。 嗯嗯,扯遠(yuǎn)了,我今天只想說說:static 與 yield。 先來(lái)說說 static 關(guān)鍵字。本篇只講靜態(tài)方法的使用與后期...

    thursday 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<