php 找出哪个类调用了另一个类中的方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1214043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Find out which class called a method in another class
提问by Botto
Is there a way in PHP to find out what object called what method in another object.
PHP中有没有办法找出哪个对象在另一个对象中调用了什么方法。
Exmaple:
例子:
class Foo
{
public function __construct()
{
$bar = new Bar();
$bar->test();
}
}
class Bar
{
public function test()
{
}
}
$foo = new Foo();
Would there be a way for me to find out that the test method was called from the foo object?
有没有办法让我发现测试方法是从 foo 对象调用的?
回答by Pascal MARTIN
you could use debug_backtrace, a bit like this :
BTW, take a look at the comments on the manual page : there are some useful functions and advices given ;-)
你可以使用debug_backtrace,有点像这样:
顺便说一句,看看手册页上的评论:有一些有用的功能和建议;-)
class Foo
{
public function __construct()
{
$bar = new Bar();
$bar->test();
}
}
class Bar
{
public function test()
{
$trace = debug_backtrace();
if (isset($trace[1])) {
// $trace[0] is ourself
// $trace[1] is our caller
// and so on...
var_dump($trace[1]);
echo "called by {$trace[1]['class']} :: {$trace[1]['function']}";
}
}
}
$foo = new Foo();
The var_dumpwould output :
该var_dump会输出:
array
'file' => string '/home/squale/developpement/tests/temp/temp.php' (length=46)
'line' => int 29
'function' => string '__construct' (length=11)
'class' => string 'Foo' (length=3)
'object' =>
object(Foo)[1]
'type' => string '->' (length=2)
'args' =>
array
empty
and the echo:
和echo:
called by Foo :: __construct
But, as nice as it might look like, I am not sure it should be used as a "normal thing" in your application... Seems odd, actually : with a good design, a method should not need to know what called it, in my opinion.
但是,尽管它看起来不错,但我不确定它是否应该在您的应用程序中用作“正常事物”......看起来很奇怪,实际上:设计良好,方法不需要知道它叫什么, 在我看来。
回答by Alex Rashkov
Here is one liner solution
这是一种衬垫解决方案
list(, $caller) = debug_backtrace(false, 2);
As of PHP7 this won't work based on the docs: http://php.net/manual/en/function.list.phpas we cannot have empty properties, here is a small update:
从 PHP7 开始,根据文档,这将不起作用:http://php.net/manual/en/function.list.php因为我们不能有空属性,这里有一个小的更新:
list($childClass, $caller) = debug_backtrace(false, 2);
回答by Buttle Butkus
You could also have the calling object pass itself as an argument
您还可以让调用对象将自身作为参数传递
e.g.
例如
class Foo
{
public function __construct()
{
$bar = new Bar();
$bar->test($this);
}
}
class Bar
{
public function test()
{
}
}
$foo = new Foo();
I got this idea from the book "Design Patterns: elements of reusable object-oriented software" by Erich Gamma, et al, on page 278 in the discussion on the "Mediator" structural pattern.
我从 Erich Gamma 等人的书“设计模式:可重用面向对象软件的元素”中得到这个想法,在第 278 页的“中介者”结构模式的讨论中。
The point of the pattern is to reduce the number of many-to-many connections between a bunch of objects/classes. You create a mediator class that all those classes treat as a hub. That way the classes don't need to know about each other. The mediator handles the interactions. For the mediator to be informed of changes in the classes it tracks, they can pass themselves as arguments, or the mediator can be implemented using the "Observer" pattern.
该模式的重点是减少一堆对象/类之间的多对多连接的数量。您创建一个中介类,所有这些类都将其视为集线器。这样,类就不需要相互了解。中介处理交互。为了让中介知道它跟踪的类的变化,它们可以将自己作为参数传递,或者可以使用“观察者”模式实现中介。
2018 EDIT:
2018 年编辑:
I sometimes use interfaces with the above code, like this:
我有时会使用带有上述代码的接口,如下所示:
interface someInterface // many classes may implement this interface
{
public function giveMeBar();
}
class Foo implements someInterface
{
public function __construct()
{
$bar = new Bar();
$bar->test($this);
}
public function giveMeBar() {
return 'Bar';
}
}
class Bar
{
public function test(someInterface $a)
{
echo $a->giveMeBar();
}
}
$foo = new Foo(); // prints "Bar"
回答by Yuval Karmi
You can probably achieve this with a debug backtrace, though this seems kind of hackish.
您可能可以通过debug backtrace来实现这一点,尽管这看起来有点骇人听闻。
Your alternative option is to pass a parameter to that class and tell it where it is being called from, when you instantiate the class from within another.
您的替代选择是将参数传递给该类,并在您从另一个类中实例化该类时告诉它从何处调用它。
回答by Randolpho
At the very least, you could use debug_backtraceand analyze that to find the calling method.
至少,您可以使用debug_backtrace并对其进行分析以找到调用方法。
I think you should also be able to do it using the reflection API, but it's been too long since I've used PHP and I don't remember exactly how. The links should at least get you started, however.
我认为您也应该能够使用反射 API来做到这一点,但是自从我使用 PHP 以来已经太久了,我不记得确切的方法了。但是,这些链接至少应该可以帮助您入门。
回答by SasQ
@Pascal MARTIN: Yes, in normal applicacions it's probably not needed. But sometimes it could be useful. Consider an example from my own app:
@Pascal MARTIN:是的,在正常应用中可能不需要它。但有时它可能很有用。考虑我自己的应用程序中的一个示例:
There's a Controller subclass which can use a Template object to prepare its output. Every template has a name to refer it to. When a Controller needs a Template, it asks the TemplateManager for it by giving that name as a parameter. But there could be many template files with that name for different Controllers. Controlers are used as plugins, and may be written by different users, so the names used by them can't be controlled to no collide with each other. Namespaces for templates are needed. So TemplateManager, which is a factory for Template objects, needs the template name and the namespace name to locate the proper template source file. This namespace is related to the particular Controller's class name.
有一个 Controller 子类,它可以使用 Template 对象来准备其输出。每个模板都有一个名称来引用它。当 Controller 需要模板时,它会通过将该名称作为参数向 TemplateManager 询问它。但是对于不同的控制器,可能会有许多具有该名称的模板文件。控制器作为插件使用,可能由不同的用户编写,因此不能控制它们使用的名称不相互冲突。需要模板的命名空间。因此,TemplateManager 作为 Template 对象的工厂,需要模板名称和命名空间名称来定位正确的模板源文件。此命名空间与特定控制器的类名相关。
But, in most cases, each Controller will be using templates from its own namespace and only in rare cases from other namespaces. So specifying the namespace in each call to TemplateManager::getTemplate() each time would be a mess. It's better if namespace is optional and defaults to... the Controller which calls the TemplateManager::getTemplate()!And here's a good place for knowing the caller.
但是,在大多数情况下,每个 Controller 将使用来自其自己的命名空间的模板,并且仅在极少数情况下使用来自其他命名空间的模板。因此,在每次调用 TemplateManager::getTemplate() 时指定命名空间将是一团糟。如果命名空间是可选的并且默认为...调用 TemplateManager::getTemplate() 的控制器会更好!这里是了解来电者的好地方。
Of course the caller Controller could pass itself or its name as a parameter, but it doesn't really differ much from passing the namespace name. It couldn't be optional in either way.
当然,调用者控制器可以将自身或其名称作为参数传递,但它与传递命名空间名称并没有太大区别。无论哪种方式,它都不能是可选的。
But if you can know the caller, you can use that information to default the namespace automatically inside the getTemplate(), without even bothering the caller. It doesn't have to know how getTemplate() is handling it in its inside and how does it know the proper default namespace. He only needs to know that it does, and that it can pass any other namespace optionally if it really needs to.
但是,如果您知道调用者,则可以使用该信息在 getTemplate() 中自动默认命名空间,而无需打扰调用者。它不必知道 getTemplate() 如何在其内部处理它以及它如何知道正确的默认命名空间。他只需要知道它确实如此,并且如果确实需要,它可以选择性地传递任何其他名称空间。
回答by Lo?c BRIED
This function does the job without debug_backtrace :
此函数无需 debug_backtrace 即可完成工作:
/*
usage :
some code...
getRealCallClass(__FUNCTION__);
some code...
*/
function getRealCallClass($functionName) //Parameter value must always be __FUNCTION__
{
try
{
throw new exception();
}
catch(exception $e)
{
$trace = $e->getTrace();
$bInfunction = false;
foreach($trace as $trace_piece)
{
if ($trace_piece['function'] == $functionName)
{
if (!$bInfunction)
$bInfunction = true;
}
elseif($bInfunction) //found !!!
{
return $trace_piece['class'];
}
}
}
}
回答by fballer87
var_dump(getClass($this));
Used in a method in namespace B this will give you the class that called a method in namespace B from namespace A.
在命名空间 B 中的方法中使用,这将为您提供从命名空间 A 中调用命名空间 B 中的方法的类。

