日韩在线不卡一区二区三区四区五区,欧美视频一区二区三,欧美视频中文字幕一区二区,高端 精品 国产 探花,亚欧无吗一二三四五六区
RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
怎么從0開(kāi)始構(gòu)建一個(gè)PHP框架

這篇文章主要講解了“怎么從0開(kāi)始構(gòu)建一個(gè)PHP框架”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“怎么從0開(kāi)始構(gòu)建一個(gè)PHP框架”吧!

創(chuàng)新互聯(lián)是一家專(zhuān)注于網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)與策劃設(shè)計(jì),津市網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專(zhuān)注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專(zhuān)業(yè)建站公司;建站業(yè)務(wù)涵蓋:津市等地區(qū)。津市做網(wǎng)站價(jià)格咨詢(xún):13518219792

如何構(gòu)建一個(gè)自己的PHP框架

為什么我們要去構(gòu)建一個(gè)自己的PHP框架?可能絕大多數(shù)的人都會(huì)說(shuō)“市面上已經(jīng)那么多的框架了,還造什么輪子?”。我的觀點(diǎn)“造輪子不是目的,造輪子的過(guò)程中汲取到知識(shí)才是目的”。

那怎樣才能構(gòu)建一個(gè)自己的PHP框架呢?大致流程如下:

入口文件 ----> 注冊(cè)自加載函數(shù)         ----> 注冊(cè)錯(cuò)誤(和異常)處理函數(shù)         ----> 加載配置文件         ----> 請(qǐng)求         ----> 路由          ---->(控制器 <----> 數(shù)據(jù)模型)         ----> 響應(yīng)         ----> json         ----> 視圖渲染數(shù)據(jù)

除此之外我們還需要單元測(cè)試、NOSQL支持、接口文檔支持、一些輔助腳本等。最終我的框架目錄如下:

框架目錄一覽

app                             [PHP應(yīng)用目錄](méi) ├── demo                        [模塊目錄](méi) │   ├── controllers             [控制器目錄](méi) │   │      └── Index.php        [默認(rèn)控制器文件,輸出json數(shù)據(jù)] │   ├── logics                  [邏輯層,主要寫(xiě)業(yè)務(wù)邏輯的地方] │   │   ├── exceptions          [異常目錄](méi) │   │   ├── gateway          [一個(gè)邏輯層實(shí)現(xiàn)的gateway演示] │   │   ├── tools               [工具類(lèi)目錄](méi) │   │   └── UserDefinedCase.php [注冊(cè)框架加載到路由前的處理用例] │   └── models                  [數(shù)據(jù)模型目錄](méi) │       └── TestTable.php       [演示模型文件,定義一一對(duì)應(yīng)的數(shù)據(jù)模型] ├── config                      [配置目錄](méi) │    ├── demo                   [模塊配置目錄](méi) │    │   ├── config.php         [模塊自定義配置] │    │   └── route.php          [模塊自定義路由] │    ├── common.php             [公共配置] │    ├── database.php           [數(shù)據(jù)庫(kù)配置] │    └── nosql.php              [nosql配置] docs                            [接口文檔目錄](méi) ├── apib                        [Api Blueprint] │    └── demo.apib              [接口文檔示例文件] ├── swagger                     [swagger] framework                       [Easy PHP核心框架目錄](méi) ├── exceptions                  [異常目錄](méi) │      ├── CoreHttpException.php[核心http異常] ├── handles                     [框架運(yùn)行時(shí)掛載處理機(jī)制類(lèi)目錄](méi) │      ├── Handle.php           [處理機(jī)制接口] │      ├── ErrorHandle.php      [錯(cuò)誤處理機(jī)制類(lèi)] │      ├── ExceptionHandle.php  [未捕獲異常處理機(jī)制類(lèi)] │      ├── ConfigHandle.php     [配置文件處理機(jī)制類(lèi)] │      ├── NosqlHandle.php      [nosql處理機(jī)制類(lèi)] │      ├── LogHandle.php        [log機(jī)制類(lèi)] │      ├── UserDefinedHandle.php[用戶(hù)自定義處理機(jī)制類(lèi)] │      └── RouterHandle.php     [路由處理機(jī)制類(lèi)] ├── orm                         [對(duì)象關(guān)系模型] │      ├── Interpreter.php      [sql解析器] │      ├── DB.php               [數(shù)據(jù)庫(kù)操作類(lèi)] │      ├── Model.php            [數(shù)據(jù)模型基類(lèi)] │      └── db                   [數(shù)據(jù)庫(kù)類(lèi)目錄](méi) │          └── MySQL.php        [mysql實(shí)體類(lèi)] ├── nosql                       [nosql類(lèi)目錄](méi) │    ├── Memcahed.php           [Memcahed類(lèi)文件] │    ├── MongoDB.php            [MongoDB類(lèi)文件] │    └── redis.php              [Redis類(lèi)文件] ├── App.php                     [框架類(lèi)] ├── Container.php               [服務(wù)容器] ├── Helper.php                  [框架助手類(lèi)] ├── Load.php                    [自加載類(lèi)] ├── Request.php                 [請(qǐng)求類(lèi)] ├── Response.php                [響應(yīng)類(lèi)] ├── run.php                     [框架應(yīng)用啟用腳本] frontend                        [前端源碼和資源目錄](méi) ├── src                         [資源目錄](méi) │    ├── components             [vue組件目錄](méi) │    ├── views                  [vue視圖目錄](méi) │    ├── images                 [圖片] │    ├── ... ├── app.js                      [根js] ├── app.vue                     [根組件] ├── index.template.html         [前端入口文件模板] ├── store.js                    [vuex store文件] public                          [公共資源目錄,暴露到萬(wàn)維網(wǎng)] ├── dist                        [前端build之后的資源目錄,build生成的目錄,不是發(fā)布分支忽略該目錄](méi) │    └── ... ├── index.html                  [前端入口文件,build生成的文件,不是發(fā)布分支忽略該文件] ├── index.php                   [后端入口文件] runtime                         [臨時(shí)目錄](méi) ├── logs                        [日志目錄](méi) ├── build                       [php打包生成phar文件目錄](méi) tests                           [單元測(cè)試目錄](méi) ├── demo                        [模塊名稱(chēng)] │      └── DemoTest.php         [測(cè)試演示] ├── TestCase.php                [測(cè)試用例] vendor                          [composer目錄](méi) .git-hooks                      [git鉤子目錄](méi) ├── pre-commit                  [git pre-commit預(yù)commit鉤子示例文件] ├── commit-msg                  [git commit-msg示例文件] .babelrc                        [babel配置文件] .env                            [環(huán)境變量文件] .gitignore                      [git忽略文件配置] build                           [php打包腳本] cli                             [框架cli模式運(yùn)行腳本] LICENSE                         [lincese文件] logo.png                        [框架logo圖片] composer.json                   [composer配置文件] composer.lock                   [composer lock文件] package.json                    [前端依賴(lài)配置文件] phpunit.xml                     [phpunit配置文件] README-CN.md                    [中文版readme文件] README.md                       [readme文件] webpack.config.js               [webpack配置文件] yarn.lock                       [yarn lock文件]

框架模塊說(shuō)明:

入口文件

定義一個(gè)統(tǒng)一的入口文件,對(duì)外提供統(tǒng)一的訪(fǎng)問(wèn)文件。對(duì)外隱藏了內(nèi)部的復(fù)雜性,類(lèi)似企業(yè)服務(wù)總線(xiàn)的思想。

// 載入框架運(yùn)行文件  require('../framework/run.php');

[ file: public/index.php ]

自加載模塊

使用spl_autoload_register函數(shù)注冊(cè)自加載函數(shù)到__autoload隊(duì)列中,配合使用命名空間,當(dāng)使用一個(gè)類(lèi)的時(shí)候可以自動(dòng)載入(require)類(lèi)文件。注冊(cè)完成自加載邏輯后,我們就可以使用use和配合命名空間申明對(duì)某個(gè)類(lèi)文件的依賴(lài)。

[ file: framework/Load.php ]

錯(cuò)誤和異常模塊

腳本運(yùn)行期間:

  • 錯(cuò)誤:

通過(guò)函數(shù)set_error_handler注冊(cè)用戶(hù)自定義錯(cuò)誤處理方法,但是set_error_handler不能處理以下級(jí)別錯(cuò)誤,E_ERROR、  E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 調(diào)用  set_error_handler() 函數(shù)所在文件中產(chǎn)生的大多數(shù)  E_STRICT。所以我們需要使用register_shutdown_function配合error_get_last獲取腳本終止執(zhí)行的***錯(cuò)誤,目的是對(duì)于不同錯(cuò)誤級(jí)別和致命錯(cuò)誤進(jìn)行自定義處理,例如返回友好的提示的錯(cuò)誤信息。

[ file: framework/hanles/ErrorHandle.php ]

異常:

通過(guò)函數(shù)set_exception_handler注冊(cè)未捕獲異常處理方法,目的捕獲未捕獲的異常,例如返回友好的提示和異常信息。

[ file: framework/hanles/ExceptionHandle.php ]

配置文件模塊

加載框架自定義和用戶(hù)自定義的配置文件。

[ file: framework/hanles/ConfigHandle.php ]

輸入和輸出

  • 定義請(qǐng)求對(duì)象:包含所有的請(qǐng)求信息

  • 定義響應(yīng)對(duì)象:申明響應(yīng)相關(guān)信息

框架中所有的異常輸出和控制器輸出都是json格式,因?yàn)槲艺J(rèn)為在前后端完全分離的今天,這是很友善的,目前我們不需要再去考慮別的東西。

[ file: framework/Request.php ]

[ file: framework/Response.php ]

路由模塊

通過(guò)用戶(hù)訪(fǎng)問(wèn)的url信息,通過(guò)路由規(guī)則執(zhí)行目標(biāo)控制器類(lèi)的的成員方法。我在這里把路由大致分成了四類(lèi):

傳統(tǒng)路由

domain/index.php?module=Demo&contoller=Index&action=test&username=test

pathinfo路由

domain/demo/index/modelExample

用戶(hù)自定義路由

// 定義在config/moduleName/route.php文件中,這個(gè)的this指向RouterHandle實(shí)例 $this->get('v1/user/info', function (Framework\App $app) {     return 'Hello Get Router'; });

微單體路由

我在這里詳細(xì)說(shuō)下這里所謂的微單體路由,面向SOA和微服務(wù)架構(gòu)大行其道的今天,有很多的團(tuán)隊(duì)都在向服務(wù)化邁進(jìn),但是服務(wù)化過(guò)程中很多問(wèn)題的復(fù)雜度都是指數(shù)級(jí)的增長(zhǎng),例如分布式的事務(wù),服務(wù)部署,跨服務(wù)問(wèn)題追蹤等等。這導(dǎo)致對(duì)于小的團(tuán)隊(duì)從單體架構(gòu)走向服務(wù)架構(gòu)難免困難重重,所以有人提出來(lái)了微單體架構(gòu),按照我的理解就是在一個(gè)單體架構(gòu)的SOA過(guò)程,我們把微服務(wù)中的的各個(gè)服務(wù)還是以模塊的方式放在同一個(gè)單體中,比如:

app ├── UserService     [用戶(hù)服務(wù)模塊] ├── ContentService  [內(nèi)容服務(wù)模塊] ├── OrderService    [訂單服務(wù)模塊] ├── CartService     [購(gòu)物車(chē)服務(wù)模塊] ├── PayService      [支付服務(wù)模塊] ├── GoodsService    [商品服務(wù)模塊] └── CustomService   [客服服務(wù)模塊]

如上,我們簡(jiǎn)單的在一個(gè)單體里構(gòu)建了各個(gè)服務(wù)模塊,但是這些模塊怎么通信呢?如下:

App::$app->get('demo/index/hello', [     'user' => 'TIGERB' ]);

通過(guò)上面的方式我們就可以松耦合的方式進(jìn)行單體下各個(gè)模塊的通信和依賴(lài)了。與此同時(shí),業(yè)務(wù)的發(fā)展是難以預(yù)估的,未來(lái)當(dāng)我們向SOA的架構(gòu)遷移時(shí),很簡(jiǎn)單,我們只需要把以往的模塊獨(dú)立成各個(gè)項(xiàng)目,然后把App實(shí)例get方法的實(shí)現(xiàn)轉(zhuǎn)變?yōu)镽PC或者REST的策略即可,我們可以通過(guò)配置文件去調(diào)整對(duì)應(yīng)的策略或者把自己的,第三方的實(shí)現(xiàn)注冊(cè)進(jìn)去即可。

[ file: framework/hanles/RouterHandle.php ]

傳統(tǒng)的MVC模式提倡為MCL模式

傳統(tǒng)的MVC模式包含model-view-controller層,絕大多時(shí)候我們會(huì)把業(yè)務(wù)邏輯寫(xiě)到controller層或model層,但是慢慢的我們會(huì)發(fā)現(xiàn)代碼難以閱讀、維護(hù)、擴(kuò)展,所以我在這里強(qiáng)制增加了一個(gè)logics層。至于,邏輯層里怎么寫(xiě)代碼怎么,完全由你自己定義,你可以在里面實(shí)現(xiàn)一個(gè)工具類(lèi),你也可以在里面再新建子文件夾并在里面構(gòu)建你的業(yè)務(wù)邏輯代碼,你甚至可以實(shí)現(xiàn)一個(gè)基于責(zé)任連模式的網(wǎng)關(guān)(我會(huì)提供具體的示例)。這樣看來(lái),我們的最終結(jié)構(gòu)是這樣的:

  • M: models, 職責(zé)只涉及數(shù)據(jù)模型相關(guān)操作

  • C: controllers, 職責(zé)對(duì)外暴露資源,前后端分離架構(gòu)下controllers其實(shí)就相當(dāng)于json格式的視圖

  • L: logics, 職責(zé)靈活實(shí)現(xiàn)所有業(yè)務(wù)邏輯的地方

logics邏輯層

邏輯層實(shí)現(xiàn)網(wǎng)關(guān)示例:

我們?cè)趌ogics層目錄下增加了一個(gè)gateway目錄,然后我們就可以靈活的在這個(gè)目錄下編寫(xiě)邏輯了。gateway的結(jié)構(gòu)如下:

gateway                     [Logics層目錄下gateway邏輯目錄](méi)   ├── Check.php             [接口]   ├── CheckAppkey.php       [檢驗(yàn)app key]   ├── CheckArguments.php    [校驗(yàn)必傳參數(shù)]   ├── CheckAuthority.php    [校驗(yàn)訪(fǎng)問(wèn)權(quán)限]   ├── CheckFrequent.php     [校驗(yàn)訪(fǎng)問(wèn)頻率]   ├── CheckRouter.php       [網(wǎng)關(guān)路由]   ├── CheckSign.php         [校驗(yàn)簽名]   └── Entrance.php          [網(wǎng)關(guān)入口文件]

網(wǎng)關(guān)入口類(lèi)主要負(fù)責(zé)網(wǎng)關(guān)的初始化,代碼如下:

// 初始化一個(gè):必傳參數(shù)校驗(yàn)的check $checkArguments   =  new CheckArguments(); // 初始化一個(gè):app key check $checkAppkey      =  new CheckAppkey(); // 初始化一個(gè):訪(fǎng)問(wèn)頻次校驗(yàn)的check $checkFrequent    =  new CheckFrequent(); // 初始化一個(gè):簽名校驗(yàn)的check $checkSign        =  new CheckSign(); // 初始化一個(gè):訪(fǎng)問(wèn)權(quán)限校驗(yàn)的check $checkAuthority   =  new CheckAuthority(); // 初始化一個(gè):網(wǎng)關(guān)路由規(guī)則 $checkRouter      =  new CheckRouter();  // 構(gòu)成對(duì)象鏈 $checkArguments->setNext($checkAppkey)                ->setNext($checkFrequent)                ->setNext($checkSign)                ->setNext($checkAuthority)                ->setNext($checkRouter);  // 啟動(dòng)網(wǎng)關(guān) $checkArguments->start(     APP::$container->getSingle('request') );

實(shí)現(xiàn)完成這個(gè)gateway之后,我們?nèi)绾卧诳蚣苤腥ナ褂媚?在logic層目錄中我提供了一個(gè)user-defined的實(shí)體類(lèi),我們把gateway的入口類(lèi)注冊(cè)到UserDefinedCase這個(gè)類(lèi)中,示例如下:

/**  * 注冊(cè)用戶(hù)自定義執(zhí)行的類(lèi)  *  * @var array  */ private $map = [     // 演示 加載自定義網(wǎng)關(guān)     'App\Demo\Logics\Gateway\Entrance' ];

這樣這個(gè)gateway就可以工作了。接著說(shuō)說(shuō)這個(gè)UserDefinedCase類(lèi),UserDefinedCase會(huì)在框架加載到路由機(jī)制之前被執(zhí)行,這樣我們就可以靈活的實(shí)現(xiàn)一些自定義的處理了。這個(gè)gateway只是個(gè)演示,你完全可以天馬行空的組織你的邏輯~

視圖View去哪了?由于選擇了完全的前后端分離和SPA(單頁(yè)應(yīng)用), 所以傳統(tǒng)的視圖層也因此去掉了,詳細(xì)的介紹看下面。

[ file: app/* ]

使用Vue作為視圖

源碼目錄

完全的前后端分離,數(shù)據(jù)雙向綁定,模塊化等等的大勢(shì)所趨。這里我把我自己開(kāi)源的vue前端項(xiàng)目結(jié)構(gòu) easy-vue  移植到了這個(gè)項(xiàng)目里,作為視圖層。我們把前端的源碼文件都放在frontend目錄里,詳細(xì)如下,你也可以自己定義:

frontend                        [前端源碼和資源目錄,這里存放我們整個(gè)前端的源碼文件] ├── src                         [資源目錄](méi) │    ├── components             [編寫(xiě)我們的前端組件] │    ├── views                  [組裝我們的視圖] │    ├── images                 [圖片] │    ├── ... ├── app.js                      [根js] ├── app.vue                     [根組件] ├── index.template.html         [前端入口文件模板] └── store.js                    [狀態(tài)管理,這里只是個(gè)演示,你可以很靈活的編寫(xiě)文件和目錄](méi)

build步驟

yarn install  DOMAIN=http://你的域名 npm run dev

編譯后

build成功之后會(huì)生成dist目錄和入口文件index.html在public目錄中。非發(fā)布分支.gitignore文件會(huì)忽略這些文件,發(fā)布分支去除忽略即可。

public [公共資源目錄,暴露到萬(wàn)維網(wǎng)]  ├── dist [前端build之后的資源目錄,build生成的目錄,不是發(fā)布分支忽略該目錄](méi) │ └── ...  ├── index.html [前端入口文件,build生成的文件,不是發(fā)布分支忽略該文件]

[ file: frontend/* ]

數(shù)據(jù)庫(kù)對(duì)象關(guān)系映射

數(shù)據(jù)庫(kù)對(duì)象關(guān)系映射ORM(Object Relation  Map)是什么?按照我目前的理解:顧名思義是建立對(duì)象和抽象事物的關(guān)聯(lián)關(guān)系,在數(shù)據(jù)庫(kù)建模中model實(shí)體類(lèi)其實(shí)就是具體的表,對(duì)表的操作其實(shí)就是對(duì)model實(shí)例的操作??赡芙^大多數(shù)的人都要問(wèn)“為什么要這樣做,直接sql語(yǔ)句操作不好嗎?搞得這么麻煩!”,我的答案:直接sql語(yǔ)句當(dāng)然可以,一切都是靈活的,但是從一個(gè)項(xiàng)目的   可復(fù)用,可維護(hù), 可擴(kuò)展  出發(fā),采用ORM思想處理數(shù)據(jù)操作是理所當(dāng)然的,想想如果若干一段時(shí)間你看見(jiàn)代碼里大段的難以閱讀且無(wú)從復(fù)用的sql語(yǔ)句,你是什么樣的心情。

市面上對(duì)于ORM的具體實(shí)現(xiàn)有thinkphp系列框架的Active Record,yii系列框架的Active  Record,laravel系列框架的Eloquent(據(jù)說(shuō)是***雅的),那我們這里言簡(jiǎn)意賅就叫ORM了。接著為ORM建模,首先是ORM客戶(hù)端實(shí)體DB:通過(guò)配置文件初始化不同的db策略,并封裝了操作數(shù)據(jù)庫(kù)的所有行為,最終我們通過(guò)DB實(shí)體就可以直接操作數(shù)據(jù)庫(kù)了,這里的db策略目前我只實(shí)現(xiàn)了mysql(負(fù)責(zé)建立連接和db的底層操作)。接著我們把DB實(shí)體的sql解析功能獨(dú)立成一個(gè)可復(fù)用的sql解析器的trait,具體作用:把對(duì)象的鏈?zhǔn)讲僮鹘馕龀删唧w的sql語(yǔ)句。***,建立我們的模型基類(lèi)model,model直接繼承DB即可。***的結(jié)構(gòu)如下:

├── orm                         [對(duì)象關(guān)系模型] │      ├── Interpreter.php      [sql解析器] │      ├── DB.php               [數(shù)據(jù)庫(kù)操作類(lèi)] │      ├── Model.php            [數(shù)據(jù)模型基類(lèi)] │      └── db                   [數(shù)據(jù)庫(kù)類(lèi)目錄](méi) │          └── Mysql.php        [mysql實(shí)體類(lèi)]

DB類(lèi)使用示例

/**  * DB操作示例  *  * findAll  *  * @return void  */ public function dbFindAllDemo() {     $where = [         'id'   => ['>=', 2],     ];     $instance = DB::table('user');     $res      = $instance->where($where)                          ->orderBy('id asc')                          ->limit(5)                          ->findAll(['id','create_at']);     $sql      = $instance->sql;      return $res; }

Model類(lèi)使用示例

// controller 代碼 /**  * model example  *  * @return mixed  */ public function modelExample() {     try {          DB::beginTransaction();         $testTableModel = new TestTable();          // find one data         $testTableModel->modelFindOneDemo();         // find all data         $testTableModel->modelFindAllDemo();         // save data         $testTableModel->modelSaveDemo();         // delete data         $testTableModel->modelDeleteDemo();         // update data         $testTableModel->modelUpdateDemo([                'nickname' => 'easy-php'             ]);         // count data         $testTableModel->modelCountDemo();          DB::commit();         return 'success';      } catch (Exception $e) {         DB::rollBack();         return 'fail';     } }  //TestTable model /**  * Model操作示例  *  * findAll  *  * @return void  */ public function modelFindAllDemo() {     $where = [         'id'   => ['>=', 2],     ];     $res = $this->where($where)                 ->orderBy('id asc')                 ->limit(5)                 ->findAll(['id','create_at']);     $sql = $this->sql;      return $res; }

[ file: framework/orm/* ]

服務(wù)容器模塊

什么是服務(wù)容器?

服務(wù)容器聽(tīng)起來(lái)很浮,按我的理解簡(jiǎn)單來(lái)說(shuō)就是提供一個(gè)第三方的實(shí)體,我們把業(yè)務(wù)邏輯需要使用的類(lèi)或?qū)嵗⑷氲竭@個(gè)第三方實(shí)體類(lèi)中,當(dāng)需要獲取類(lèi)的實(shí)例時(shí)我們直接通過(guò)這個(gè)第三方實(shí)體類(lèi)獲取。

服務(wù)容器的意義?

用設(shè)計(jì)模式來(lái)講:其實(shí)不管設(shè)計(jì)模式還是實(shí)際編程的經(jīng)驗(yàn)中,我們都是強(qiáng)調(diào)“高內(nèi)聚,松耦合”,我們做到高內(nèi)聚的結(jié)果就是每個(gè)實(shí)體的作用都是極度專(zhuān)一,所以就產(chǎn)生了各個(gè)作用不同的實(shí)體類(lèi)。在組織一個(gè)邏輯功能時(shí),這些細(xì)化的實(shí)體之間就會(huì)不同程度的產(chǎn)生依賴(lài)關(guān)系,對(duì)于這些依賴(lài)我們通常的做法如下:

class Demo {     public function __construct()     {         // 類(lèi)demo直接依賴(lài)RelyClassName         $instance = new RelyClassName();     } }

這樣的寫(xiě)法沒(méi)有什么邏輯上的問(wèn)題,但是不符合設(shè)計(jì)模式的“最少知道原則”,因?yàn)橹g產(chǎn)生了直接依賴(lài),整個(gè)代碼結(jié)構(gòu)不夠靈活是緊耦合的。所以我們就提供了一個(gè)第三方的實(shí)體,把直接依賴(lài)轉(zhuǎn)變?yōu)橐蕾?lài)于第三方,我們獲取依賴(lài)的實(shí)例直接通過(guò)第三方去完成以達(dá)到松耦合的目的,這里這個(gè)第三方充當(dāng)?shù)慕巧皖?lèi)似系統(tǒng)架構(gòu)中的“中間件”,都是協(xié)調(diào)依賴(lài)關(guān)系和去耦合的角色。***,這里的第三方就是所謂的服務(wù)容器。

在實(shí)現(xiàn)了一個(gè)服務(wù)容器之后,我把Request,Config等實(shí)例都以單例的方式注入到了服務(wù)容器中,當(dāng)我們需要使用的時(shí)候從容器中獲取即可,十分方便。使用如下:

// 注入單例 App::$container->setSingle('別名,方便獲取', '對(duì)象/閉包/類(lèi)名');  // 例,注入Request實(shí)例 App::$container->setSingle('request', function () {     // 匿名函數(shù)懶加載     return new Request(); }); // 獲取Request對(duì)象 App::$container->getSingle('request');

[ file: framework/Container ]

Nosql模塊

提供對(duì)nosql的支持,提供全局單例對(duì)象,借助我們的服務(wù)容器我們?cè)诳蚣軉?dòng)的時(shí)候,通過(guò)配置文件的配置把需要的nosql實(shí)例注入到服務(wù)容器中。目前我們支持redis/memcahed/mongodb。

如何使用?如下,

// 獲取redis對(duì)象 App::$container->getSingle('redis'); // 獲取memcahed對(duì)象 App::$container->getSingle('memcahed'); // 獲取mongodb對(duì)象 App::$container->getSingle('mongodb');

[ file: framework/nosql/* ]

接口文檔生成和接口模擬模塊

通常我們寫(xiě)完一個(gè)接口后,接口文檔是一個(gè)問(wèn)題,我們這里使用Api  Blueprint協(xié)議完成對(duì)接口文檔的書(shū)寫(xiě)和mock(可用),同時(shí)我們配合使用Swagger通過(guò)接口文檔實(shí)現(xiàn)對(duì)接口的實(shí)時(shí)訪(fǎng)問(wèn)(目前未實(shí)現(xiàn))。

Api Blueprint接口描述協(xié)議選取的工具是snowboard,具體使用說(shuō)明如下:

接口文檔生成說(shuō)明

cd docs/apib  ./snowboard html -i demo.apib -o demo.html -s  open the website, http://localhost:8088/

接口mock使用說(shuō)明

cd docs/apib  ./snowboard mock -i demo.apib  open the website, http://localhost:8087/demo/index/hello

[ file: docs/* ]

單元測(cè)試模塊

基于phpunit的單元測(cè)試,寫(xiě)單元測(cè)試是個(gè)好的習(xí)慣。

如何使用?

tests目錄下編寫(xiě)測(cè)試文件,具體參考tests/demo目錄下的DemoTest文件,然后運(yùn)行:

vendor/bin/phpunit

測(cè)試斷言示例:

/**  * 演示測(cè)試  */ public function testDemo() {     $this->assertEquals(         'Hello Easy PHP',         // 執(zhí)行demo模塊index控制器hello操作,斷言結(jié)果是不是等于'Hello Easy PHP'          App::$app->get('demo/index/hello')     ); }

phpunit斷言文檔語(yǔ)法參考

[ file: tests/* ]

Git鉤子配置

目的規(guī)范化我們的項(xiàng)目代碼和commit記錄。

  • 代碼規(guī)范:配合使用php_codesniffer,在代碼提交前對(duì)代碼的編碼格式進(jìn)行強(qiáng)制驗(yàn)證。

  • commit-msg規(guī)范:采用ruanyifeng的commit msg規(guī)范,對(duì)commit msg進(jìn)行格式驗(yàn)證,增強(qiáng)git  log可讀性和便于后期查錯(cuò)和統(tǒng)計(jì)log等, 這里使用了 Treri 的commit-msg腳本,Thx~。

[ file: ./git-hooks/* ]

輔助腳本

cli腳本

以命令行的方式運(yùn)行框架,具體見(jiàn)使用說(shuō)明。

build腳本

打包PHP項(xiàng)目腳本,打包整個(gè)項(xiàng)目到runtime/build目錄,例如:

runtime/build/App.20170505085503.phar  

[ file: ./build ]

如何使用?

執(zhí)行:

  • composer install

  • chmod -R 777 runtime

網(wǎng)站服務(wù)模式:

  • 步驟 1: yarn install

  • 步驟 2: DOMAIN=http://localhost:666 npm run demo

  • 步驟 3: cd public

  • 步驟 4: php -S localhost:666

訪(fǎng)問(wèn)網(wǎng)站:http://localhost:666/index.html

訪(fǎng)問(wèn)接口:http://localhost:666/Demo/Index/hello

demo如下:

客戶(hù)端腳本模式:

php cli --method= --= ...  例如, php cli --method=demo.index.get --username=easy-php

獲取幫助:

使用命令 php cli 或者 php cli --help

問(wèn)題和貢獻(xiàn)

不足的地方還有很多,如果大家發(fā)現(xiàn)了什么問(wèn)題,可以給我提 issue 或者PR。

或者你覺(jué)著在這個(gè)框架實(shí)現(xiàn)的細(xì)節(jié)你想了解的,一樣可以給我提 issue ,后面我會(huì)總結(jié)成相應(yīng)的文章分享給大家。

如何貢獻(xiàn)?

cp ./.git-hooks/* ./git/hooks

然后正常發(fā)起PR即可, 所有的commit我都會(huì)進(jìn)行代碼格式(psr)驗(yàn)證和commit-msg驗(yàn)證,如果發(fā)生錯(cuò)誤,請(qǐng)按照提示糾正即可。

TODO

  • 懶加載優(yōu)化框架加載流程

  • 性能測(cè)試和優(yōu)化

  • 變更Helper助手類(lèi)的成員方法為框架函數(shù),簡(jiǎn)化使用提高生產(chǎn)效率

  • 提供更友善的開(kāi)發(fā)api幫助

  • 模塊支持?jǐn)?shù)據(jù)庫(kù)nosql自定義配置

  • 支持mysql主從配置

  • ORM提供更多鏈?zhǔn)讲僮鱝pi

  • 框架log行為進(jìn)行級(jí)別分類(lèi)

  • 想辦法解決上線(xiàn)部署是配置文件問(wèn)題

  • 基于phar文件和git webhook自動(dòng)化打包部署

感謝各位的閱讀,以上就是“怎么從0開(kāi)始構(gòu)建一個(gè)PHP框架”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)怎么從0開(kāi)始構(gòu)建一個(gè)PHP框架這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!


網(wǎng)站標(biāo)題:怎么從0開(kāi)始構(gòu)建一個(gè)PHP框架
文章出自:http://biofuelwatch.net/article/jigoho.html
日韩在线不卡一区二区三区四区五区,欧美视频一区二区三,欧美视频中文字幕一区二区,高端 精品 国产 探花,亚欧无吗一二三四五六区