关于路由配置中使用call_user_func和参数自动注入冲突问题

redsky

问题描述

实现目标:路由自动匹配:模块/控制器/方法,主要参考了以下两个地址
https://github.com/walkor/webman/issues/54
https://www.workerman.net/q/6685

目前碰到问题,在路由中匹配完成后,通过call_user_func来调用方法,而在方法中我原先使用了自动注入,现在两者冲突了。

程序代码

路由匹配实现

Route::group('/{module}', function () {
    Route::group("/{controller}", function () {
        Route::post("/{action}", function ($request, $module, $controller, $action) {
            return toRoute($request, $module, $controller, $action, 'create');
        });
        Route::delete("/{action}", function ($request, $module, $controller, $action) {
            return toRoute($request, $module, $controller, $action, 'delete');
        });
        Route::get("/{action}", function ($request, $module, $controller, $action) {
            return toRoute($request, $module, $controller, $action, 'get');
        });
        Route::put("/{action}", function ($request, $module, $controller, $action) {
            return toRoute($request, $module, $controller, $action, 'update');
        });
    });
});

function toRoute($request, $module, $controller, $action, $method = 'get') {

    $class_name = 'app\\api\\controller\\'.$module.'\\'.ucfirst($controller).'Controller';
    if(!class_exists($class_name)){
        return json(['code'=>404,'msg'=>config('app.debug')?'控制器:'.$class_name.' 不存在':'请求资源不存在']);
    }

    $action = $method . ucfirst($action);
    if (!method_exists($class_name, $action)) {
        return json(['code'=>404,'msg'=>config('app.debug')?'控制器方法:'.$action.' 不存在':'请求资源不存在']);
    }
    $controller = new $class_name;
    $request->controller = $class_name;
    return call_user_func([$controller, $action], $request);
}

方法部分代码

public function getListData ($request, Student $student)
    {
        return $this->success();
    }

截图报错信息里报错文件相关代码

Too few arguments to function app\api\controller\student\StudentController::getListData()

操作系统及workerman/webman等框架组件具体版本

webman : 1.4.7
php-di: 6.3

558 1 0
1个回答

walkor

https://www.workerman.net/doc/webman/di.html#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%B3%A8%E5%85%A5
手册有讲,必须是由框架或者php-di创建的实例才能完成依赖自动注入,手动new的实例无法完成依赖自动注入,如需注入,需要使用support\Container接口替换new语句

  • redsky 2022-12-10

    改了通过:
    $controller = Container::get($class_name);
    $request->controller = $class_name;
    $request->action = $action;
    return call_user_func([$controller, $action], $request);
    结果还是报错:
    Too few arguments to function app\api\controller\ding\ApiController::getListData(), 1 passed

    是我的用法错了吗?请老大指点,从thinkphp转webman,还在适应中!

  • walkor 2022-12-10

    call_user_func属于手动调用,手动调用需要传完整参数,无法自动注入,这个任何框架都一样。
    还有webman现在支持复杂的路由匹配,包括模块/控制器/方法这种,不需要手动设置路由。

  • redsky 2022-12-10

    老大,因为我有一些特殊需求,根据用户的请求类型,然后在方法前自动带上请求类型,比如访问路由为:system/api/menu,请求方法为get,那么该路由定位的控制器应该是:app/api/controller/system/Apicontroller,方法是:getMenu。内置的路由应该无法满足我的需求,所以需要自己做下处理。

    现在我改为:
    function toRoute($request, $module, $controller, $action, $method = 'get') {
    $class_name = "app\api\controller\".$module."\".ucfirst($controller)."Controller";
    if(!class_exists($class_name)){
    return json(['code'=>404,'msg'=>config('app.debug')?'控制器:'.$class_name.' 不存在':'请求资源不存在']);
    }
    $action = $method . ucfirst($action);
    if (!method_exists($class_name, $action)) {
    return json(['code'=>404,'msg'=>config('app.debug')?'控制器方法:'.$action.' 不存在':'请求资源不存在']);
    }
    return Container::get($class_name);
    }

    但是又出现了新的问题:

    Object of class app\api\controller\***** could not be converted to string

  • walkor 2022-12-10

    控制器返回的数据必须时reposne对象,不能是其他对象

  • redsky 2022-12-10

    老大,我控制器返回的就是Response对象呀,目前我确实不清楚该怎么去修改代码,才能使用,还请老大能指点迷津,谢谢!

  • walkor 2022-12-10

    return Container::get($class_name); 返回的是控制器实例,不是response实例。

年代过于久远,无法发表回答
🔝