确定调用call_user_func_array

时间:2016-11-19 13:59:23

标签: php

是否可以找到调用call_user_func_array方法的类的名称?这是一个例子:

// ClassA
public static function __callStatic($method, $args)
{
    return call_user_func_array([ClassB::some_method(static::$some_arg), $method], $args);
}

// ClassB
public static function some_method($some_arg) {
    // how do I find out that some_method was called by ClassA?
}

目标是让some_method知道它是由ClassA调用的。另请注意,ClassB::some_method(static::$some_arg)会静态调用该方法,然后将$method中的call_user_func_array与其链接。

在旁注中,我尝试将call_user_func_array替换为return DB::some_method(static::$some_arg)->$method(extract($args));,但它没有按预期工作。有什么原因吗?

修改

我对最初的问题有些轻微的疑惑。想象一下现在有一个班级ClassA_Child

class ClassA_Child extends ClassA {}

ClassA_Child现在可以调用ClassB方法 - some_method。电话会是

ClassA_Child::some_method;

这是有效的,因为ClassA_ChildClassA的子类。但是,如果我执行以下操作:

// ClassB
public static function some_method($some_arg) {
    $bt = debug_backtrace();
    $caller_class = (isset($bt[1]['class']) ? $bt[1]['class'] : null);
    echo $caller_class; // ClassA, and NOT ClassA_Child!
}

请注意,回溯表示基类some_method调用了ClassA,而不是ClassA_Child。有办法解决吗?

1 个答案:

答案 0 :(得分:1)

一些介绍应该是这个答案。首先讨论(那些程序员在啤酒前面的社交活动)会很高兴为什么你会想要这么复杂的间接参考,我使用相当复杂的ORM并且他们没有&# 39; t需要这么多级别的间接和抽象。

另一个重要的注意事项是,有人可能会发表一些非常哲学的论点,即你应该采用debug_backtrace()解决方案。这确实是不好的做法,但猜猜看,我也在使用它。只是被警告,它是非常脆弱的编码,有很多情况准备好背刺。

以下是相关代码:

class A {
  static $some_arg = "ciao";

  public static function __callStatic($method, $args) {
    return call_user_func_array(array(B::some_method(static::$some_arg), $method), $args);
  }
}

class B {
  public static function some_method($some_arg) {
    print "B::some_method (" . $some_arg . ")\n";

    // obtain the caller class
    $bt = debug_backtrace();
    $caller_class = (isset($bt[1]['class']) ? $bt[1]['class'] : null);
    print ".. i was called by " . $caller_class . "\n";

    return "C";
  }
}

class C {
  public static function other_method($arg1, $arg2) {
    print "C::other_method called\n";
  }
}

A::other_method(10, 20);

输出:

B::some_method (ciao)
.. i was called by A
C::other_method called

更新#2

如果在__callStatic()的子类而不是直接在ClassA(如ClassA)中调用ClassA_Child::doSomething(),则可以将以下代码行替换为获取此信息。请注意,如果脚本直接调用__callStatic()本身(无论如何都不应该发生),这种更改(将调用堆栈增加一个额外级别)将失败

$caller_class = (isset($bt[2]['class']) ? $bt[2]['class'] : null);

<强>更新

我必须编辑我的回答#34;旁注&#34;部分问题。我错了,因为我认为some_method()会返回一个静态类名(基本上是一个字符串),而它实际上会返回一个实例。

好吧,在这种情况下,如果你愿意,你绝对可以抛弃call_user_func_array(),但是使用那个是我的首选解决方案。你唯一的错误就是提取($ args)部分,该功能做你想的,它实际上做了一些完全不同的事情,请查看手册页。

这里你需要的是扩展运算符,如下例所示:

class B {
  static function factory() {
    print "called B::factory()\n";
    return new C();
  }
}

class C {
  function m($a, $b) {
    print "called c::m() a=$a b=$b\n";
  }
}

$func_name = "m";
$func_args = array(10, 20);
B::factory()->$func_name(...$func_args);

输出:

called B::factory()
called c::m() a=10 b=20