app()->invoke() 是 ThinkPHP 5.1+(含 TP6/8)里底层反射调用方法,核心用于执行任意类的方法/函数/闭包,并自动做依赖注入,常用于框架内部调度或跨类复用逻辑(但不推荐滥用跨控制器调用)。

下面从“作用 → 用法 → 示例 → 源码 → 避坑”讲清楚。


一、它是什么(作用)

app() 是助手函数,返回 think\App 实例;invoke()App 的方法,底层靠 PHP反射 + 容器依赖注入 实现:

  • 实例化类(自动注入构造器依赖)
  • 调用指定方法(自动注入方法参数依赖)
  • 支持:控制器方法、服务类方法、闭包、函数

等价于:

  1. // 底层封装
  2. $app = new \think\App();
  3. $app->invoke([类, 方法], 参数);

二、基本用法(TP5.1/6/8 通用)

1)调用类方法(最常用)

格式:

  1. // 方式1:数组 [类名, 方法名]
  2. app()->invoke(['完整类名', '方法名'], [参数数组]);
  3. // 方式2:字符串 "类名@方法名"
  4. app()->invoke('完整类名@方法名', [参数数组]);

2)调用闭包/函数

  1. // 闭包
  2. app()->invoke(function($name){
  3. return 'Hello ' . $name;
  4. }, ['豆包']);
  5. // 全局函数
  6. app()->invoke('trim', [' abc ']);

三、实战示例(直接复制可用)

示例1:调用服务类方法(推荐)

  1. // app/service/AuthService.php
  2. namespace app\service;
  3. class AuthService {
  4. public function check($uid) {
  5. return $uid > 0;
  6. }
  7. }
  8. // 控制器中调用
  9. $result = app()->invoke(['app\service\AuthService', 'check'], [1001]);
  10. // 或字符串形式
  11. $result = app()->invoke('app\service\AuthService@check', [1001]);

示例2:跨控制器调用(不推荐,仅应急)

  1. // app/controller/NotifyController.php
  2. namespace app\controller;
  3. class NotifyController {
  4. public function sendMail($to) {
  5. return '发送给:' . $to;
  6. }
  7. }
  8. // IndexController 中调用
  9. $result = app()->invoke(['app\controller\NotifyController', 'sendMail'], ['a@qq.com']);

示例3:自动依赖注入(DI)

  1. // 服务类(依赖 Request)
  2. namespace app\service;
  3. use think\Request;
  4. class UserService {
  5. public function getInfo(Request $request, $uid) {
  6. return ['uid' => $uid, 'ip' => $request->ip()];
  7. }
  8. }
  9. // 调用时不用传 Request,自动注入
  10. $result = app()->invoke('app\service\UserService@getInfo', [1001]);

四、源码核心(TP6 简化版)

think\App.php 里的 invoke 最终调用 invokeMethod

  1. public function invoke($method, array $vars = []) {
  2. return $this->invokeMethod($method, $vars);
  3. }
  4. protected function invokeMethod($method, $vars) {
  5. // 1. 解析类和方法
  6. list($class, $method) = $this->parseMethod($method);
  7. // 2. 实例化类(依赖注入构造器)
  8. $instance = $this->make($class);
  9. // 3. 反射方法,绑定参数(依赖注入方法参数)
  10. $reflect = new \ReflectionMethod($instance, $method);
  11. $args = $this->bindParams($reflect, $vars);
  12. // 4. 执行方法
  13. return $reflect->invokeArgs($instance, $args);
  14. }

核心:make() 实例化 + bindParams() 自动注入参数


五、避坑指南(重点)

  1. 跨控制器调用不推荐

    • invoke 不执行路由、中间件、控制器初始化(如 initialize
    • 控制器里的 $this->request$this->view 可能未初始化,导致报错
  2. 优先用服务类,而非控制器互调

    • 复用逻辑抽成 app/service/xxx.php,再用 invoke 调用,更安全、解耦
  3. 参数严格匹配

    • 方法参数顺序要和 $vars 数组顺序一致
    • 依赖注入的参数(如 Request不用传,框架自动注入
  4. TP5.0 无此方法

    • TP5.0 用 action(),TP5.1+ 移除 action(),改用 app()->invoke()

六、和 call_user_func 的区别

  • call_user_func不支持依赖注入,需手动实例化类、传参
  • app()->invoke容器级调用,自动实例化 + 自动注入依赖,符合 ThinkPHP 的 DI 设计