如何在PHP中跟踪类链中的根对象

0 php oop inheritance chain

class Header
{
    public function __construct()
    {
        global $app;
        print($app->config);
    }
}

class Modules
{
    public function __construct()
    {
        $this->header = new Header();
    }
}

class Project
{
    public $config = "config";

    public function __construct()
    {
        $this->modules = new Modules();
    }
}

$app = new Project();
Run Code Online (Sandbox Code Playgroud)

现在,如果我想从范围内访问根对象(Project类的实例,即)Header,我必须记住我为实例选择的名称(可能会有所不同)并使用global关键字引用它.但我觉得这只是一个快速修复.我需要一种可靠的方法来访问根对象,从中构造当前对象(及其父对象).

换句话说,我需要访问$app内部,$app->modules->header给出名称app本身是可变的事实,链的长度也是动态的.

我可以访问父级的命名空间,parent::但是有类似的东西会很高兴first_ancestor::.

irc*_*ell 12

所以,本着回答问题的精神,当然有办法(警告:这里是龙):

function YouAreAnIdiotIfYouDoThisForReal($skip = 0) {
    $bt = debug_backtrace();
    if (isset($bt[1]['function']) && $bt[1]['function'] === "__construct") {
        // called from constructor, so skip it!
        $skip++;
    }
    foreach ($bt as $stack) {
        if (isset($stack['function']) && $stack['function'] === "__construct" && $skip-- <= 0) {
            return $stack['object'];
        }
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

可以这样使用:

class Header
{
    public function __construct()
    {
        $this->project = YouAreAnIdiotIfYouDoThisForReal(1);
        $this->modules = YouAreAnIdiotIfYouDoThisForReal();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这就是你所要求的.但是,请在任何情况,你应该真正做到这一点.

认真.

我不能强调如果你这样做会有多糟糕.

很脆弱.

而且很脏.

并依赖于调试功能.

和施工顺序之间的硬编码关系.

和其他垃圾.

真正的答案:

相反,重构接受显式依赖:

class Header
{
    public function __construct(Project $project, Modules $modules)
    {
        $this->project = $project;
        $this->modules = $modules;
    }
}

class Modules
{
    public function __construct(Project $project)
    {
        $this->project = $project;
        $this->header = new Header($project, $this);
    }
}

class Project
{
    public $config = "config";

    public function __construct()
    {
        $this->modules = new Modules($this);
    }
}
Run Code Online (Sandbox Code Playgroud)

您的依赖关系是明确的,并且一切都清楚地知道发生了什么.

甚至更好

更好的是,完全从等式中删除New:

class Header
{
    public function __construct(Project $project)
    {
        $this->project = $project;
    }
}

class Modules
{
    public function __construct(Header $header)
    {
        $this->header = $header;
    }
}

class Project
{
    public $config = "config";

    public function __construct()
    {
    }

    public function setModules(Modules $modules) {
        $this->modules = $modules;
    }
}

$project = new Project();
$headers = new Header($project);
$modules = new Modules($headers);
$project->setModules($modules);
Run Code Online (Sandbox Code Playgroud)

现在,您的代码本身将完全隔离,而不依赖于任何东西.您可以根据需要覆盖每个依赖项(例如,当您想要将假项目注入时进行测试Header())...

这称为依赖注入.

说真的,不要使用第一种方法.它更像是一个笑话而不是任何东西(展示PHP的力量,但是好主,不,那是邪恶的......