天天看点

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服务进行面向对象编程.废话不多说,直接复制粘贴~

此处内容需要评论回复后(审核通过)方可阅读。