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

5n0oy7gb  于 2023-02-28  发布在  PHP
关注(0)|答案(8)|浏览(205)

在PHP中有没有一种方法可以找出哪个对象调用了另一个对象中的哪个方法。
示例:

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

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

有没有什么方法可以让我发现test方法是从foo对象调用的?

q9yhzks0

q9yhzks01#

你可以使用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();

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

echo

called by Foo :: __construct

但是,尽管它看起来不错,但我不确定它是否应该在您的应用程序中作为“正常的东西”使用......实际上,这似乎很奇怪:在我看来,有了好的设计,方法就不需要知道是什么调用了它。

nc1teljy

nc1teljy2#

这是一个线性解

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

从PHP7开始,根据文档这是不起作用的:http://php.net/manual/en/function.list.php因为我们不能有空属性,这里是一个小的更新:

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

yvt65v4c3#

您还可以让调用对象将自身作为参数传递
例如:

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

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

我从《设计模式:Erich Gamma等人在第278页关于“Mediator”结构模式的讨论中介绍了“可重用面向对象软件的元素”。
这种模式的目的是减少一组对象/类之间的多对多连接。您创建一个中介类,所有这些类都将其视为一个中心。这样,类就不需要知道彼此。中介处理交互。为了让中介了解它跟踪的类中的更改,它们可以将自己作为参数传递。或者可以使用“观察者”模式来实现中介器。
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"
8e2ybdfx

8e2ybdfx4#

您可能可以使用debug backtrace来实现这一点,尽管这看起来有点笨拙。
另一种选择是,当您从另一个类中示例化该类时,向该类传递一个参数,并告诉它从何处调用该类。

pbwdgjma

pbwdgjma5#

至少,您可以使用debug_backtrace并对其进行分析以找到调用方法。
我想你应该也能用reflection API来做这件事,但是我已经很久没有用PHP了,我不记得具体是怎么做的了。

hiz5n14c

hiz5n14c6#

@帕斯卡·马丁:是的,在一般的应用程序中可能不需要它。但有时候它可能会很有用。考虑一下我自己的应用程序中的一个例子:
有一个Controller子类,它可以使用Template对象来准备它的输出。每个模板都有一个名称来引用它。当一个Controller需要一个模板时,它通过将该名称作为参数来请求TemplateManager。但是对于不同的Controller,可能有许多具有该名称的模板文件。Controller被用作插件,并且可能由不同的用户编写。因此它们使用的名称不能被控制为彼此不冲突。模板的名称空间是必需的。因此TemplateManager是Template对象的工厂,它需要模板名称和名称空间名称来定位正确的模板源文件。这个名称空间与特定的Controller的类名相关。
但是,在大多数情况下,每个Controller都将使用来自自己的命名空间的模板,只有在极少数情况下使用来自其他命名空间的模板。因此,每次调用TemplateManager::getTemplate()时指定命名空间会很麻烦。如果命名空间是可选的,并且默认为...**调用TemplateManager::getTemplate()的Controller!**这里是了解调用者的好地方。
当然,调用者Controller可以将其自身或其名称作为参数传递,但这与传递名称空间名称实际上没有太大区别,无论哪种方式都不是可选的。
但是如果你知道调用者,你可以使用这个信息在getTemplate()中自动默认命名空间,甚至不用麻烦调用者。它不需要知道getTemplate()是如何在它内部处理它的,以及它是如何知道正确的默认命名空间的。他只需要知道它是这样做的,并且如果真的需要,它可以选择性地传递任何其他命名空间。

jtjikinw

jtjikinw7#

此函数在不使用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'];
           }
      }
   }
}
mpgws1up

mpgws1up8#

var_dump(getClass($this));

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

相关问题