Search code examples
phpsingleton

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


I am writing a custom PHP Application from scratch and for some classes I use the singleton pattern, because I need some information to be calculated one time and them I just use them.

Today I wrote a big part of my application and when I tested it all in all, it threw me the following error:

Maximum function nesting level of '100' reached, aborting.

I did some tests and found that error is generated by something like this:

File index.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();

File Bar.php

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

To my mind it is valid because F() was called before and it should have the instance of Foo in the static variable, and I believe it should somehow work, but it doesn't.

I feel lost now. How can I make it to work or at least how can I change something to have similar behavior?


Solution

  • The $instance value remains null all the time. Why? Well have a look what happens before you assign the instance to $instance.

    Before $instance has any different value you call $bar->doSomething(); again.

    This means you run F() again but $instance is still null. Now you instantiate Foo again but guess what $instance is still null.

    Try this:

    <?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();
    

    If you use the singleton pattern, make sure the class itself keeps track of whether it got initialized or not. Letting an external source handle this can cause a lot of problems (as you just experienced).