PHP 单例:达到最大函数嵌套级别“100”,中止


PHP Singleton: Maximum function nesting level of '100' reached, aborting

我从头开始编写一个自定义的PHP应用程序,对于某些类,我使用单例模式,因为我需要计算一次信息,而我只是使用它们。

今天我写了我的应用程序的很大一部分,当我测试它时,它给我抛出了以下错误:

达到最大函数嵌套级别"100",正在中止。

我做了一些测试,发现错误是由这样的东西产生的:

文件索引.php

class Foo
{
    public function __construct()
    {
        if(!class_exists('Bar', false))
        {
            require 'Bar.php';
        }
        $bar = new Bar;
        $bar->doSomething();
    }
    public function showSomeInformation()
    {
        // information
    }
}
function F()
{
    static $instance = null;
    if(is_null($instance))
    {
        $instance = new Foo;
    }
    return $instance;
}
F();

文件栏.php

class Bar
{
    public function doSomething()
    {
        F()->showSomeInformation();
    }
}

在我看来,它是有效的,因为之前调用过F()并且它应该在静态变量中具有 Foo 的实例,我相信它应该以某种方式工作,但它没有。

我现在感到迷茫。我怎样才能让它工作,或者至少我怎样才能改变一些东西来具有类似的行为?

$instance值始终保持null。为什么?好吧,在将实例分配给$instance之前,看看会发生什么。

$instance具有任何不同的值之前,您再次调用$bar->doSomething();

这意味着您再次运行F(),但$instance仍然null。现在你再次实例化Foo,但猜猜什么$instance仍然是空的。

试试这个:

<?php class Foo
{
    static $instance = null;
    public function __construct()
    {
        if(!class_exists('Bar', false))
        {
            require 'Bar.php';
        }
        self::$instance = $this;
        $bar = new Bar;
        $bar->doSomething(self::$instance);
    }
    public function showSomeInformation()
    {
        // information
    }
}
class Bar
{
    public function doSomething($instance)
    {
        F($instance)->showSomeInformation();
    }
}
function F($instance = null)
{
    if(is_null($instance))
    {
        $instance = new Foo;
    }
    return $instance;
}
F();

如果使用单例模式,请确保类本身跟踪它是否已初始化。 让外部源处理此问题可能会导致很多问题(正如您刚刚遇到的那样)。

无限递归发生在 foo 的构造函数中:

function F()
{
    static $instance = null;
    if(is_null($instance))
    {
        $instance = new Foo;
        echo("Never reached'n");
        if( is_null($instance) )
        {
            echo("Still null!'n");
        }
    }
    return $instance;
}

第一个 F(); 调用不会创建 Foo。它将调用 Foo 的构造函数,这将在返回 Foo 对象之前调用 F(),但 F() 在另一个 Foo 上调用构造函数,它将永远做同样的事情,因此没有新的 Foo 会从 F() 返回。所以我们用完了堆栈。

下面是 PHP 中一个理智的单例模式示例:设计模式

我不喜欢单例模式,我想,如果你有一点经验并从单元测试开始,你也会讨厌它。但是该模式并不像您尝试的那样有效。

class MySingletonClass
{
    private static $instance;
    // Make the constructor protected, to prevent direct instantiation
    protected function __construct() {}
    /**
    * @return MySingletonClass
    */
    public static function getInstance()
    {
         if (!self::$instance) {
             self::$instance = new self(); // new static() would we valid too, relevant for extending (late state binding)
         }
         return self::$instance;
    }
    public function getSomething()
    {
         if (!$this->calculated) {
             $this->calculated = $this->calculateSomething();
         }
         return $this->calculated;
    }
}
echo MySingletonClass::getInstance()->getSomething();