Php 找出哪个类调用了另一个类中的方法

Php 找出哪个类调用了另一个类中的方法,php,Php,PHP中有没有一种方法可以找出什么对象在另一个对象中调用了什么方法 Exmaple: class Foo { public function __construct() { $bar = new Bar(); $bar->test(); } } class Bar { public function test() { } } $foo = new Foo(); 有没有办法让我知道这个测试方法是从foo对象调用的?你可能可以用一个函数来实现这一点,

PHP中有没有一种方法可以找出什么对象在另一个对象中调用了什么方法

Exmaple:

class Foo
{
  public function __construct()
  {
    $bar = new Bar();
    $bar->test();
  }
}

class Bar
{
  public function test()
  {
  }
}
$foo = new Foo();

有没有办法让我知道这个测试方法是从foo对象调用的?

你可能可以用一个函数来实现这一点,尽管这看起来有点黑客


您的另一种选择是,当您从另一个类中实例化该类时,将参数传递给该类并告诉它调用的位置。

至少,您可以使用并分析该参数来找到调用方法

我认为您也应该能够使用,但是我已经很久没有使用PHP了,我不记得具体是如何使用的。然而,这些链接至少应该让你开始学习

您可以使用,有点像这样:
顺便说一句,看看手册页上的评论:有一些有用的功能和建议;-)

var\u 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
回声

called by Foo :: __construct
但是,尽管它看起来很好,但我不确定它是否应该在您的应用程序中作为“正常的东西”使用。。。事实上,这似乎很奇怪:在我看来,一个好的设计方法不需要知道它的名称。

@Pascal MARTIN: 是的,在正常应用中可能不需要。但有时它可能是有用的。 从我自己的应用程序中考虑一个例子:

有一个控制器子类可以使用模板对象来准备其输出。每个模板都有一个可供引用的名称。当控制器需要模板时,它会通过将该名称作为参数向TemplateManager请求模板。 但是,对于不同的控制器,可能有许多具有该名称的模板文件。控制器作为插件使用,可能由不同的用户编写,因此不能控制它们使用的名称,以免相互冲突。需要模板的名称空间。 因此TemplateManager是模板对象的工厂,需要模板名称和命名空间名称来定位正确的模板源文件。此命名空间与特定控制器的类名相关

但是,在大多数情况下,每个控制器将使用来自其自己名称空间的模板,只有在极少数情况下使用来自其他名称空间的模板。因此,每次调用TemplateManager::getTemplate()时都要指定名称空间,这将是一场混乱。如果名称空间是可选的并且默认为调用TemplateManager::getTemplate()的控制器这里是认识来电者的好地方

当然,调用方控制器可以将自身或其名称作为参数传递,但它与传递名称空间名称没有太大区别。这两种方式都不是可选的


但是,如果您知道调用方,则可以使用该信息在getTemplate()中自动默认名称空间,而不会打扰调用方。它不必知道getTemplate()如何在其内部处理它,也不必知道它如何知道正确的默认名称空间。他只需要知道它是这样做的,并且如果确实需要,它可以选择性地传递任何其他名称空间。

您也可以让调用对象本身作为参数传递

e、 g

我是从Erich Gamma等人在第278页讨论“中介”结构模式时写的《设计模式:可重用面向对象软件的元素》一书中得到这个想法的

该模式的要点是减少一组对象/类之间的多对多连接的数量。创建一个中介类,所有这些类都将其视为中心。这样一来,学生们就不需要互相了解了。调解人处理交互。为了让中介器知道它跟踪的类中的更改,它们可以将自己作为参数传递,或者可以使用“观察者”模式实现中介器

2018年编辑:

我有时使用上面代码的接口,如下所示:

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"

这里有一个线性解决方案

list(, $caller) = debug_backtrace(false, 2);
从PHP7开始,基于文档这将不起作用:因为我们不能有空属性,这里有一个小的更新:

list($childClass, $caller) = debug_backtrace(false, 2);

此函数在没有调试回溯的情况下执行作业:

/*
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'];
           }
      }
   }
}

在命名空间B中的方法中使用,这将为您提供从命名空间a调用命名空间B中的方法的类。

我以前研究过这个问题,当时似乎回溯是唯一的选项。工作示例总是很好的+1. :)谢谢;-)(这也是我没有得到第一个答案的原因,但是,至少,这样我也有一点乐趣;-))谢谢你的例子。“是的,我在某种程度上同意,方法不需要知道,但我有其他人在我写的东西的基础上编写代码,我想让他们的生活更轻松,”他说。我认为使用debug有点不成熟,但是谢谢你,你让我对调试功能有了很好的了解,这是我以前从未真正做过的事情。不客气:-)谢谢你解释你为什么需要它!(另一个解决方案可以考虑使用一个调试器,比如Xdebug提供的一个可以与Eclipse PDT集成的调试器,例如,它的答案),你不想写吗?列表(,$caller)=调试回溯(false,2)//还是浪费时间?@JxAxMxIxN这是一个公平的观点,可以节省一些执行周期,改变了。爱一行人。如果仅从主脚本或一个上下文调用,则感谢“致命错误:未捕获满足\Service\error\ErrorException:未定义的偏移量:1 in…”。问题是list(),它需要2个偏移量。如果您将debug_backtrace()的结果放入一个var中并打印出来,那么很明显:)这也是我能想到的最明智的解决方案。Debug_backtrace看起来像是一种黑客行为,我知道在PHP中没有其他方法可以导航调用堆栈,这不是最好的方法。
list($childClass, $caller) = debug_backtrace(false, 2);
/*
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'];
           }
      }
   }
}
var_dump(getClass($this));