是否可以找到调用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_Child
是ClassA
的子类。但是,如果我执行以下操作:
// 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
。有办法解决吗?
答案 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