Laravel 使用 swoole 协程遇到的坑

最近在用laravel-s改造手头上的一个laravel项目,作为这块目前最火的轮子,确实好用,赞一下作者。由于目前所处理的项目需要调用大量api,使用同步串行调用效率低下,因此开始尝试使用swoole的协程客户端来调用api。

这里我本地的环境如下:

Component Version
PHP 7.1.17
Swoole 2.1.2
Laravel Framework 5.5.40

先来个demo体验一下:

<?php

namespace App\Http\Controllers;

class TestController extends Controller
{
    public function index()
    {
        $cli = new \Swoole\Coroutine\Http\Client('127.0.0.1', 80);
        $cli->setHeaders([
            'Host' => 'test.me',
        ]);
        $cli->get('/');
        $result = $cli->body;
        $cli->close();

        return response()->json($result);
    }
}

启动请求之后发现卡死,这下懵逼了,以前在其他地方都是可以用的协程客户端,这里不能用了,WTF。在群里求助,群主提及到不能在魔术方法和call_user_func之类的方法里使用(官方链接)。一语惊醒梦中人,laravel这个框架可是这类方法横行,于是研究了下Controller类的执行方式。框架在执行Controller时,会通过Illuminate\Routing\Controller类的callAction方法执行具体的Controller类的方法,而这个方法如下:

/**
 * Execute an action on the controller.
 *
 * @param string $method
 * @param array  $parameters
 *
 * @return \Symfony\Component\HttpFoundation\Response
 */
public function callAction($method, $parameters)
{
    return call_user_func_array([$this, $method], $parameters);
}

总算找到问题所在了,接下来便是解决问题。其实解决问题的方式swoole的文档里也写了,使用\Swoole\Coroutine::call_user_func\Swoole\Coroutine::call_user_func_array代替即可。那么我们只需要在App\Http\Controllers\Controller中重写一下callAction方法,代码如下:

public function callAction($method, $parameters)
{
    return \Swoole\Coroutine::call_user_func_array([$this, $method], $parameters);
}

注意如果在__call()这样的魔术方法里面需要使用$obj->$method(...$arguments)这种方式去处理用\Swoole\Coroutine::call_user_func_array还是会出现问题。

Done!

目前只是遇到这个坑,以后遇到再更新。

本文章首发在 Laravel China 社区

只要全力以赴就无所谓失败