Laravel 使用 swoole 協程遇到的坑

zhengzean發表於2018-05-22

最近在用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!

目前只是遇到這個坑,以後遇到再更新。

只要全力以赴就無所謂失敗

相關文章