Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can 2 singleton classes reference each other?

Tags:

oop

php

singleton

Why does this not work? Shouldn't each instance simply reference each other once?

class foo {
    private static $instance;
    private function __construct() {
    $test = bar::get_instance();
    }

    public static function get_instance() {
        if (empty(self::$instance)) {
            self::$instance = new foo();
        }
        return self::$instance;
    }
}

class bar {
    private static $instance;
    public function __construct() {
    $test = foo::get_instance();
    }

    public static function get_instance() {
        if (empty(self::$instance)) {
            self::$instance = new bar();
        }
        return self::$instance;
    }
}

$test = foo::get_instance();
like image 852
pmm Avatar asked Sep 14 '25 07:09

pmm


1 Answers

You have what's known as a circular-dependency. A needs B to complete to construct, and B needs A to complete to construct. So it goes round and round forever.

Basically, what's happening is that self::$instance on each class doesn't get populated until new class() finishes. So in the constructor, you're calling the other getInstance. But every time you hit get_instance(), self::$instance is still null because the previous new never finsihed. And round and round you go. It will keep going until the end.

Instead, add it in after construction:

class foo {
    private static $instance;
    private function __construct() {
    }
    private function setBar(bar $bar) {
        $this->bar = $bar;
    }

    public static function get_instance() {
        if (empty(self::$instance)) {
            self::$instance = new foo();
            self::$instance->setBar(bar::get_instance());
        }
        return self::$instance;
    }
}

class bar {
    private static $instance;
    public function __construct() {
    }
    private function setFoo(foo $foo) {
        $this->foo = $foo;
    }
    public static function get_instance() {
        if (empty(self::$instance)) {
            self::$instance = new bar();
            self::$instance->setFoo(foo::get_instance());
        }
        return self::$instance;
    }
}

However, I would really suggest re-architecting your relationships and classes so that you Inject the Dependencies rather than making self-dependent singletons.

like image 167
ircmaxell Avatar answered Sep 17 '25 02:09

ircmaxell