PHP中的单例引用和递归
我有一个主引导类(下面示例中的singleton1),它实例化了一些singleton类。在这些单例类中,我需要保留对app main类的引用,以方便快速地引用它,但这样做会给我一个:PHP中的单例引用和递归,php,recursion,singleton,nested,Php,Recursion,Singleton,Nested,我有一个主引导类(下面示例中的singleton1),它实例化了一些singleton类。在这些单例类中,我需要保留对app main类的引用,以方便快速地引用它,但这样做会给我一个: Fatal error: Maximum function nesting level of '100' reached, aborting 以下是exmaple代码: <?php class Singleton1 { private static $instance; priva
Fatal error: Maximum function nesting level of '100' reached, aborting
以下是exmaple代码:
<?php
class Singleton1 {
private static $instance;
private function __construct() {
Singleton2::instance();
}
public static function instance () {
if( !self::$instance ) {
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
public function test () {
echo 'Good.';
}
private function __clone() { }
private function __wakeup() { }
}
class Singleton2 {
private static $instance;
private $singleton1;
private function __construct() {
$this->singleton1 = Singleton1::instance();
}
public static function instance () {
if( !self::$instance ) {
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
public function test () {
$this->singleton1->test();
}
private function __clone() { }
private function __wakeup() { }
}
Singleton1::instance();
Singleton2::instance()->test();
您的代码具有以下循环:
Singleton2::__construct()
Singleton1::instance()
Singleton1::__construct()
Singleton2::instance()
Singleton2::__construct()
您可以从Singleton1
构造函数中删除Singleton2::instance()
行以查看“Good”消息。您不应该使用Singletons。它们是坏习惯(tm),因为它们引入了全局状态,这使得代码更难测试
可以通过以下方式使用控制反转重写您的示例:
<?php
// A simple Singleton for the Application
function Application()
{
static $instance = null;
if (null === $instance) {
$instance = new Application;
}
return $instance;
}
class Application
{
protected $someService;
function __construct()
{
$this->someService = new SomeService($this);
}
function test()
{
echo "Good.";
}
}
class SomeService
{
protected $application;
function __construct(Application $app)
{
$this->application = $app;
}
function test()
{
$this->application->test();
}
}
是的,当我做$this->singleton1=singleton1::instance()时,我想我刚刚得到了它;在Singleton2构造函数中,Singleton1尚未完成实例化,因此实例在静态$instance变量中还不可用,因此它尝试再次实例化它,并且再次……首先,这是一个非常糟糕的应用程序设计。你真的应该避免在你的代码中使用单例,而是支持依赖注入。也许你会理解。依赖注入是一个奇特的术语,简单的意思是:将对象传递给构造函数,或者通过setter方法。(通常通过某种类型的注册表或单例模式来对比检索对象,就像您现在所做的那样)。@fireyedboy,不,不是。如果您这样做,那么您就没有使用依赖项注入。。你之所以称它为DI,只是因为它是一个花哨的术语。@tereško:从根本上说,它是。您正在注入依赖项(通常通过构造函数或setter)。DI通常也是通过另外使用一些容器和/或工厂来创建对象的实例并将依赖项连接在一起来实现的,这并不意味着DI本身就是简单地向对象注入它们所依赖的东西。但是有一个特殊的原因,Singleton2应该由主类实例化。我想我会在第一次实例化主类时使用init方法来运行。是的,只是不要在Singleton1的构造函数中实例化Singleton2,因为Singleton1实例不是由该调用创建的。虽然这稍微好一点,你现在有一个循环引用,它仍然很糟糕。我过去经常做这样的事情,但我认为我必须对只需要实例化一次的类使用singleton。这不是一个好的实践吗?您将只创建一次应用程序实例,但您可以将应用程序设置为单例,因此服务实例也只创建一次。这里的要点是,您至少应该通过Setter/Constructor将应用程序实例注入到服务中,以避免调用application::getInstance()
,从而导致递归。@igorw这不应该是交易制动器吗?PHP应该在请求端释放应用程序使用的所有内存。虽然我也认为应该避免。