天天看點

php think swoole,Swoole相容ThinkPHP5.0hellohellohello

Swoole相容ThinkPHP5.0

羨仙. • 2019 年 06 月 24 日

下載下傳好ThinkPHP5.0後,在根目錄下建立server目錄,用于存放swoole的服務等.

建立Http服務mkdir server

cd server

touch http_server.php

直接引用之前Http的代碼吧.$server = new Swoole\Http\Server("0.0.0.0",9503);

// 設定靜态資源目錄

$server->set([

'enable_static_handler' => true,

'document_root' => "/data/wwwroot/test"

]);

$server->on('request', function($request,$response) {

$response->end("

hello

");

});

$server->start();

現在我們假如我們要在浏覽器通過live.dev:9503/index/index/qvbilam來通路的時候.如果我們不去做修改是根本找不到tp架構下index/index/qvbilam的内容的.

當我們去請求位址的時候肯定是走到代碼中request的回調裡面. 我們需要在回調函數裡處理相應的邏輯.

當我們通路thinkphp 肯定是會先通路一個入口檔案的,即pubilic/index.php.是以每次通路都時候都必須讓他經過index.php.就好了~

在swoole中有個onworkstart函數,如何了解onworkerstart函數.

現在服務設定中設定worker_num.當我們啟動這個服務的時候呢.它會走到workerstart一個事件回調裡面去,是以在啟動服務的時候應該把thinkphp架構裡面的一些内容加載到worker程序裡去.

首先看一下thinkphp5.0的index.php// [ 應用入口檔案 ]

// 定義應用目錄

define('APP_PATH', __DIR__ . '/../application/');

// 加載架構引導檔案

require __DIR__ . '/../thinkphp/start.php';

可以看到它又加載了start.php的引導檔案,檢視start.php.namespace think;

// ThinkPHP 引導檔案

// 1. 加載基礎檔案

require __DIR__ . '/base.php';

// 2. 執行應用

App::run()->send();

start.php檔案加載了一個base.php的核心檔案,是以直接把base.php加載到workerstart裡面去.這樣是為了能應用熱加載./server/http_server.php的WorkerStart如下$server->on('WorkerStart', function (swoole_server $server, $worker_id) {

// 定義應用目錄 index.php

define('APP_PATH', __DIR__ . '/../application/');

// 再去加載php的引導檔案

// 不直接複制index.php的檔案中的引入start.php.

// 是因為在start.php中還有執行應用我們不需要,是以直接引入base.php就行

// x加載基礎檔案

require __DIR__ . '/../thinkphp/base.php';

});

start.php檔案中的執行應用是應該放在request的回調裡面去,就是這行代碼// 2. 執行應用

App::run()->send();

# 添加到/server/http_server.php的request方法中

$server->on('request', function ($request, $response) use ($server) {

// 這裡一定要加上think命名空間,否則報錯

think\App::run()->send();

$response->end("

hello

");

}

直接啟動,出現報錯Warning: require(/Users/qvbi lam/Sites/liveTelecastsereras php): failed to open stream: No such file or directory in /Users/qvbi Lam/Sites/liveTelecast/server/http_server.php on line 16

PHP Fatal error: require(): Failed opening required in /Users/qvbi lam/Sites/liveTelecastserver/base php' (include_path=' .:/usr/local/Cellar/php/7.3.1/ share/php/pear') in /Users/qvbi lam/Sites/liveTelecast/server/http_server.php on line 16

Fatal error: require(): Failed opening required ' /Users/qvbi Lam/Sites/liveTelecast/server/base.php' (include_path='. :/usr/local/Cellar/pho/7.3.1/share/pho/pear') in /Users/qvbi lam/Sites/liveTelecast/server/http_server.php on line 16

别擔心哈.這是提示找不到檔案.因為從/public/index.php檔案複制的内容.是以__DIR__指的路徑就是/public.而服務是在/server,修改/server/http_server.php.$server->on('WorkerStart', function (swoole_server $server, $worker_id) {

// 定義應用目錄 index.php

define('APP_PATH', __DIR__ . '/../application/');

// 再去加載php的引導檔案

// 不直接複制index.php的檔案中的引入start.php.

// 是因為在start.php中還有執行應用我們不需要.

// 是以直接引入base.php就行

// x加載基礎檔案

require __DIR__ . '/../thinkphp/base.php';

});

這樣就沒有錯誤啦~http服務啟動

關于引用

有些人也可能會想為什麼不直接引用start.php呢?那來試試引用start.php會發生什麼.

修改application\index\controller\Index.phppublic function index()

{

return 'Index' . PHP_EOL;

}

将/server/http_server.php中WorkerStart包含的base.php替換成start.php後,啟動服務php server/http_server.php

# 輸出

Index

Index

Index

Index

Index

诶嘿~輸出了五次index/index/index()傳回内容.因為當啟動http服務的時候首先在設定中設定了5個worker程序.會啟動五次workerStart.而workerStart包含了start.php.執行了thinkphp的應用// 2. 執行應用

App::run()->send();

這個内容就會去執行架構裡的内容.因為沒有傳控制器模型方法,會自動預設為index/index/index.是以沒必要執行這個,隻需要包涵架構裡的檔案加載到worker裡面就行,真正執行的隻要在使用者請求的時候再執行,也就是說将執行應用放到 request裡面就行.

檢測服務

傳回内容

當我們通過浏覽器通路http服務的時候頁面傳回的是hello.而我們的index/index/index()傳回的是Index啊!其實是因為server/http_server.php中的request中的這行代碼# 向浏覽器輸出并結束

$response->end("

hello

");

# 修改成

// 執行應用

ob_start();

try {

think\App::run()->send();

} catch (\Exception $e) {

// 可以輸出一些錯誤。打錯誤日志什麼的。根據自己業務吧

}

$rst = ob_get_contents();

ob_end_clean();

$response->end($rst);

重新開機服務發現傳回的是index/index/index()傳回的内容

擷取傳參

修改index/index/index()public function index()

{

dump($_GET);

return 'hello 我是qvbilam_index' . PHP_EOL;

}

通路測試# 請求 get['gy'] = 1

http://live.dev:9503/index/index/index?gy=1

# 傳回結果 get['gy'] = 1

array(1){

["gy"]=>string(1)"1"

}hello 我是qvbilam_index

# 請求 get['sb'] = 'zcx'

http://live.dev:9503/index/index/index?sb=zcx

# 傳回 get['gy'] = 1 get['sb'] = 'zcx'

array(2){

["gy"]=>string(1)"1"

["sb"=>string(3)"zcx"]

}hello 我是qvbilam_index

這是因為swoole對超全局變量get,post,globals等,如果程序還在,它是不會釋放的.這樣就就很難受,我們可以對這些參數進行判斷,如果存在就删除它.

在server/http_server的request添加超全局變量處理邏輯.$server->on('request', function ($request, $response) use ($server) {

if (isset($request->server)) {

foreach ($request->server as $key => $val) {

$_SERVER[strtoupper($key)] = $val;

}

}

if (isset($request->header)) {

foreach ($request->header as $key => $val) {

$_SERVER[strtoupper($key)] = $val;

}

}

$_GET = [];

if (isset($request->get)) {

foreach ($request->get as $key => $val) {

$_GET[$key] = $val;

}

}

$_POST = [];

if (isset($request->post)) {

foreach ($request->post as $key => $val) {

$_POST[$key] = $val;

}

}

// 執行應用

ob_start();

try {

think\App::run()->send();

} catch (\Exception $e) {

// 可以輸出一些錯誤。打錯誤日志什麼的。根據自己業務吧

}

$rst = ob_get_contents();

ob_end_clean();

$response->end($rst);

});

重新開機測試,擷取傳參沒有問題啦~

路由通路

建立新方法index/index/index.phppublic function qvbilam()

{

echo 'qvbilam';

}

重新開機通路http://live.dev:9503/index/index/qvbilam

# 傳回的結果是index/index/index的内容

hello 我是qvbilam_index

# 列印$_server,再次通路傳回

Array

(

[request_method] => GET

[request_uri] => /index/index/qvbilam

[path_info] => /index/index/qvbilam

...

)

# swoole是沒有問題的

檢視thinkphp的請求.用它的内置方法echo request()->action();

$response->end($rst);

# 重新開機通路,終端傳回結果

index

是因為tp會把控制器方法放到一個變量裡去,而swoole是不會登出掉的.是以會一直通路之前的action.是以問題可能在server\http_server.php的request中.# 猜測問題所在

think\App::run()->send();

進入/thinkphp/library/think/App.php中檢視run()...

// 未設定排程資訊則進行 URL 路由檢測

if (empty($dispatch)) {

$dispatch = self::routeCheck($request, $config);

}

...

檢視routeCheck()public static function routeCheck($request, array $config)

{

$path = $request->path();

...

}

繼續檢視path(),進入/thinkphp/library/think/Request.phppublic function path()

{

if (is_null($this->path)) {

$suffix = Config::get('url_html_suffix');

$pathinfo = $this->pathinfo();

if (false === $suffix) {

// 禁止僞靜态通路

$this->path = $pathinfo;

} elseif ($suffix) {

// 去除正常的URL字尾

$this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);

} else {

// 允許任何字尾通路

$this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo);

}

}

return $this->path;

}

如果路由第一次來會把他儲存起,再進來因為沒有釋放記憶體就把第一次的請求傳回.是以讓每次請求都重新設定path.把if (is_null($this->path))的判斷去掉.這裡面還有個pathinfo()方法也是一樣的。把if (is_null($this->pathinfo))判斷去掉.

再在pathinfo()添加public function pathinfo()

{

if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] != '/') {

return ltrim($_SERVER['PATH_INFO'], '/');

}

// if (is_null($this->pathinfo)) {

...

}

重新開機通路測試,沒有問題~

面向對象優化

在server目錄下建立http.php對swoole的http服務進行面向對象程式設計.廢話不多說,直接複制粘貼~

此處内容需要評論回複後(稽核通過)方可閱讀。