從0開始構(gòu)建一個(gè)屬于你自己的PHP框架

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

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

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="9lbl4-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="9lbl4-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

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

原文轉(zhuǎn)發(fā):segmentfault.com顽耳。

10年架構(gòu)師領(lǐng)你架構(gòu)-成長(zhǎng)之路-(附面試題(含答案))

(騰訊T3-T4)打造互聯(lián)網(wǎng)PHP架構(gòu)師教程目錄大全,只要你看完妙同,薪資立馬提升2倍(持續(xù)更新)

點(diǎn)擊與我交流企鵝群.

框架目錄一覽

<pre class="public-DraftStyleDefault-pre" data-offset-key="e1osn-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="e1osn-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

框架模塊說(shuō)明:

入口文件

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="b9gb5-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="b9gb5-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

[file: public/index.php]

自加載模塊

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

[file: framework/Load.php]

錯(cuò)誤和異常模塊

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

  • 錯(cuò)誤:

通過(guò)函數(shù)set_error_handler注冊(cè)用戶自定義錯(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]

配置文件模塊

加載框架自定義和用戶自定義的配置文件萧诫。

[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ò)用戶訪問(wèn)的url信息群扶,通過(guò)路由規(guī)則執(zhí)行目標(biāo)控制器類的的成員方法及刻。我在這里把路由大致分成了四類:

傳統(tǒng)路由

<pre class="public-DraftStyleDefault-pre" data-offset-key="f3s1p-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="f3s1p-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

pathinfo路由

<pre class="public-DraftStyleDefault-pre" data-offset-key="98etm-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="98etm-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

domain/demo/index/modelExample

</pre>

</pre>

用戶自定義路由

<pre class="public-DraftStyleDefault-pre" data-offset-key="boci5-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="boci5-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

微單體路由

我在這里詳細(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è)單體中疚察,比如:

<pre class="public-DraftStyleDefault-pre" data-offset-key="20n9h-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="20n9h-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="vfgg-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="vfgg-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

通過(guò)上面的方式我們就可以松耦合的方式進(jìn)行單體下各個(gè)模塊的通信和依賴了。與此同時(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ù)邏輯寫到controller層或model層点晴,但是慢慢的我們會(huì)發(fā)現(xiàn)代碼難以閱讀感凤、維護(hù)、擴(kuò)展粒督,所以我在這里強(qiáng)制增加了一個(gè)logics層陪竿。至于,邏輯層里怎么寫代碼怎么屠橄,完全由你自己定義族跛,你可以在里面實(shí)現(xiàn)一個(gè)工具類,你也可以在里面再新建子文件夾并在里面構(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è)目錄下編寫邏輯了。gateway的結(jié)構(gòu)如下:

<pre class="public-DraftStyleDefault-pre" data-offset-key="bi7dp-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="bi7dp-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="2euub-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="2euub-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

// 初始化一個(gè):必傳參數(shù)校驗(yàn)的check checkArguments = new CheckArguments(); // 初始化一個(gè):app key checkcheckAppkey = new CheckAppkey(); // 初始化一個(gè):訪問(wèn)頻次校驗(yàn)的check checkFrequent = new CheckFrequent(); // 初始化一個(gè):簽名校驗(yàn)的checkcheckSign = new CheckSign(); // 初始化一個(gè):訪問(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')
);

</pre>

</pre>

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="5jqh1-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="5jqh1-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

/**

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

</pre>

</pre>

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

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

[file: app/*]

點(diǎn)擊與我交流企鵝群.

感謝大家一直來(lái)支持衔峰,這是我準(zhǔn)備的1000粉絲福利

【1000粉絲福利】10年架構(gòu)師分享PHP進(jìn)階架構(gòu)資料,助力大家都能30K

使用Vue作為視圖

源碼目錄

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="43s74-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="43s74-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

build步驟

<pre class="public-DraftStyleDefault-pre" data-offset-key="cd4ie-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="cd4ie-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

yarn install

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

</pre>

</pre>

編譯后

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="9ve8f-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="9ve8f-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

[file: frontend/*]

大廠2000道面試題(含答案)

PHP面試題匯總妇汗,看完這些面試題助力你面試成功,工資必有20-25K

點(diǎn)擊與我交流企鵝群.

數(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í)體類其實(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í)間你看見代碼里大段的難以閱讀且無(wú)從復(fù)用的sql語(yǔ)句,你是什么樣的心情元扔。

市面上對(duì)于ORM的具體實(shí)現(xiàn)有thinkphp系列框架的Active Record,yii系列框架的Active Record,laravel系列框架的Eloquent(據(jù)說(shuō)是最優(yōu)雅的)躯保,那我們這里言簡(jiǎn)意賅就叫ORM了。接著為ORM建模澎语,首先是ORM客戶端實(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ǔ)句减俏。最后召烂,建立我們的模型基類model,model直接繼承DB即可。最后的結(jié)構(gòu)如下:

<pre class="public-DraftStyleDefault-pre" data-offset-key="djlej-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="djlej-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

DB類使用示例

<pre class="public-DraftStyleDefault-pre" data-offset-key="esplo-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="esplo-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

/**

  • 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;
    }

</pre>

</pre>

Model類使用示例

<pre class="public-DraftStyleDefault-pre" data-offset-key="eg6j5-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="eg6j5-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

// 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;
    }

</pre>

</pre>

[file: framework/orm/*]

服務(wù)容器模塊

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

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

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

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="t373-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="t373-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

這樣的寫法沒有什么邏輯上的問(wèn)題竖共,但是不符合設(shè)計(jì)模式的“最少知道原則”,因?yàn)橹g產(chǎn)生了直接依賴俺祠,整個(gè)代碼結(jié)構(gòu)不夠靈活是緊耦合的公给。所以我們就提供了一個(gè)第三方的實(shí)體,把直接依賴轉(zhuǎn)變?yōu)橐蕾囉诘谌街┰覀儷@取依賴的實(shí)例直接通過(guò)第三方去完成以達(dá)到松耦合的目的淌铐,這里這個(gè)第三方充當(dāng)?shù)慕巧皖愃葡到y(tǒng)架構(gòu)中的“中間件”,都是協(xié)調(diào)依賴關(guān)系和去耦合的角色蔫缸。最后腿准,這里的第三方就是所謂的服務(wù)容器。

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="30su5-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="30su5-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

[file: framework/Container]

Nosql模塊

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

如何使用?如下燕偶,

<pre class="public-DraftStyleDefault-pre" data-offset-key="asaio-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="asaio-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

[file: framework/nosql/*]

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

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

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

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="bii7b-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="bii7b-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

cd docs/apib

./snowboard html -i demo.apib -o demo.html -s

open the website, http://localhost:8088/

</pre>

</pre>

接口mock使用說(shuō)明

<pre class="public-DraftStyleDefault-pre" data-offset-key="m7og-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="m7og-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

cd docs/apib

./snowboard mock -i demo.apib

open the website, http://localhost:8087/demo/index/hello

</pre>

</pre>

[file: docs/*]

單元測(cè)試模塊

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

如何使用晚唇?

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="hmln-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="hmln-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

vendor/bin/phpunit

</pre>

</pre>

測(cè)試斷言示例:

<pre class="public-DraftStyleDefault-pre" data-offset-key="5s582-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="5s582-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

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)行框架扣讼,具體見使用說(shuō)明。

build腳本

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

<pre class="public-DraftStyleDefault-pre" data-offset-key="4e89j-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="4e89j-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

runtime/build/App.20170505085503.phar

<?php // 入口文件引入包文件即可 require('runtime/build/App.20170505085503.phar');

</pre>

</pre>

[file: ./build]

如何使用?

執(zhí)行:

composer create-project tigerb/easy-php easy --prefer-dist && cd easy

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

快速開始一個(gè)demo:

<pre class="public-DraftStyleDefault-pre" data-offset-key="a5vqa-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="a5vqa-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

cd bin && php cli --run

</pre>

</pre>

demo如下:

客戶端腳本模式:

<pre class="public-DraftStyleDefault-pre" data-offset-key="b75pm-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="b75pm-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

php cli --method=<module.controller.action> --<arguments>=<value> ...

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

</pre>

</pre>

獲取幫助:

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

Swoole模式:

<pre class="public-DraftStyleDefault-pre" data-offset-key="4e55m-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="4e55m-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

cd public && php server.php

</pre>

</pre>

獲取幫助:

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

docker環(huán)境

本框架提供docker開發(fā)環(huán)境,一行命令幾分鐘構(gòu)建你的開發(fā)環(huán)境耻姥,詳細(xì)請(qǐng)點(diǎn)擊easy-env查看销钝。

性能-fpm

ab -c 100 -n 10000 "http://easy-php.local/Demo/Index/hello"

<pre class="public-DraftStyleDefault-pre" data-offset-key="3ui5q-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="3ui5q-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

Document Path: /
Document Length: 53 bytes

Concurrency Level: 100
Time taken for tests: 3.259 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1970000 bytes
HTML transferred: 530000 bytes
Requests per second: 3068.87 [#/sec] (mean)
Time per request: 32.585 [ms] (mean)
Time per request: 0.326 [ms] (mean, across all concurrent requests)
Transfer rate: 590.40 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 4
Processing: 6 32 4.0 31 68
Waiting: 6 32 4.0 31 68
Total: 8 32 4.0 31 68

Percentage of the requests served within a certain time (ms)
50% 31
66% 32
75% 33
80% 34
90% 39
95% 41
98% 43
99% 46
100% 68 (longest request)

</pre>

</pre>

性能-Swoole

ab -c 100 -n 10000 "http://easy-php.local/Demo/Index/hello"

<pre class="public-DraftStyleDefault-pre" data-offset-key="bibk2-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="bibk2-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

Concurrency Level: 100
Time taken for tests: 1.319 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1870000 bytes
HTML transferred: 160000 bytes
Requests per second: 7580.84 [#/sec] (mean)
Time per request: 13.191 [ms] (mean)
Time per request: 0.132 [ms] (mean, across all concurrent requests)
Transfer rate: 1384.39 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 5 10.6 3 172
Processing: 1 9 13.4 7 177
Waiting: 0 7 11.7 6 173
Total: 3 13 16.9 11 179

Percentage of the requests served within a certain time (ms)
50% 11
66% 12
75% 13
80% 14
90% 15
95% 17
98% 28
99% 39
100% 179 (longest request)

</pre>

</pre>

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

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

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

如何貢獻(xiàn)?

<pre class="public-DraftStyleDefault-pre" data-offset-key="cppql-0-0" style="margin: 1.4em 0px; padding: 0.88889em; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: auto; background: rgb(246, 246, 246); border-radius: 4px; color: rgb(18, 18, 18); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

<pre class="Editable-styled" data-block="true" data-editor="aednp" data-offset-key="cppql-0-0" style="margin: 0px; padding: 0px; font-size: 0.9em; word-break: normal; overflow-wrap: normal; white-space: pre; overflow: initial; background: rgb(246, 246, 246); border-radius: 0px;">

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

</pre>

</pre>

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

項(xiàng)目地址:https://github.com/TIGERB/easy-php

TODO

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

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

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

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

  • 支持mysql主從配置

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

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

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

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

  • ...

喜歡我的文章就關(guān)注我吧挽唉,持續(xù)更新中.....

以上內(nèi)容希望幫助到大家,很多PHPer在進(jìn)階的時(shí)候總會(huì)遇到一些問(wèn)題和瓶頸筷狼,業(yè)務(wù)代碼寫多了沒有方向感瓶籽,不知道該從那里入手去提升,對(duì)此我整理了一些資料埂材,包括但不限于:分布式架構(gòu)塑顺、高可擴(kuò)展、高性能、高并發(fā)严拒、服務(wù)器性能調(diào)優(yōu)扬绪、TP6,laravel裤唠,YII2挤牛,Redis,Swoole种蘸、Swoft墓赴、Kafka、Mysql優(yōu)化劈彪、shell腳本竣蹦、Docker、微服務(wù)沧奴、Nginx等多個(gè)知識(shí)點(diǎn)高級(jí)進(jìn)階干貨需要的可以免費(fèi)分享給大家,需要的可以點(diǎn)擊進(jìn)入暗號(hào):知乎长窄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末滔吠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挠日,更是在濱河造成了極大的恐慌疮绷,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚣潜,死亡現(xiàn)場(chǎng)離奇詭異冬骚,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)懂算,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門只冻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人计技,你說(shuō)我怎么就攤上這事喜德。” “怎么了垮媒?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵舍悯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我睡雇,道長(zhǎng)萌衬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任它抱,我火速辦了婚禮秕豫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抗愁。我一直安慰自己馁蒂,他們只是感情好呵晚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沫屡,像睡著了一般饵隙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沮脖,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天金矛,我揣著相機(jī)與錄音,去河邊找鬼勺届。 笑死驶俊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的免姿。 我是一名探鬼主播饼酿,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胚膊!你這毒婦竟也來(lái)了故俐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤紊婉,失蹤者是張志新(化名)和其女友劉穎药版,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喻犁,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡槽片,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肢础。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片还栓。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖乔妈,靈堂內(nèi)的尸體忽然破棺而出蝙云,到底是詐尸還是另有隱情,我是刑警寧澤路召,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布勃刨,位于F島的核電站,受9級(jí)特大地震影響股淡,放射性物質(zhì)發(fā)生泄漏身隐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一唯灵、第九天 我趴在偏房一處隱蔽的房頂上張望贾铝。 院中可真熱鬧,春花似錦、人聲如沸垢揩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)叁巨。三九已至斑匪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锋勺,已是汗流浹背蚀瘸。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庶橱,地道東北人贮勃。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像苏章,于是被迫代替她去往敵國(guó)和親寂嘉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容