4

我注意到 PHP 中单例的奇怪行为没有更好的方法来解释这一点,但有一个例子。

假设我有以下单例类:

class Singleton
{
    protected function __construct()
    {
        // Deny direct instantion!
    }
    protected function __clone()
    {
        // Deny cloning!
    }
    public static function &Instance()
    {
        static $Instance;

        echo 'Class Echo'.PHP_EOL;
        var_dump($Instance);

        if (!isset($Instance)) {
            $Instance = new self;
        }

        return $Instance;
    }
}

以及以下功能:

function Test($Init = FALSE)
{
    static $Instance;

    if ($Init === TRUE && !isset($Instance)) {
        $Instance =& Singleton::Instance();
    }

    echo 'Function Echo'.PHP_EOL;
    var_dump($Instance);

    return $Instance;
}

当我使用以下内容时:

Test(TRUE);
Test();
Singleton::Instance();

输出是:

Class Echo
NULL
Function Echo
object(Singleton)#1 (0) {
}
Function Echo
NULL
Class Echo
object(Singleton)#1 (0) {
}

如您所见,即使变量是静态的,执行后函数内部保存的引用也会丢失。另外请注意,类方法中的静态变量工作正常。

这应该是正常的还是我做错了什么?

4

2 回答 2

6

这种行为记录在案

驱动 PHP 4 的 Zend 引擎 1根据引用实现了变量的静态全局修饰符。例如,使用 global 语句在函数范围内导入的真正全局变量实际上会创建对全局变量的引用。这可能导致意外行为。

自 ZE1 以来,此行为没有改变,解决方案只是不分配对静态变量的引用,因此:

$Instance = Singleton::Instance();

更新

我简化了以下问题:

function test2($init = false, $value = null)
{
  static $test;

  if ($init) {
    $test =& $value;
  }

  var_dump($test);
}

$v = 1;

test2(true, $v);
test2();

输出:

int(1)
NULL
于 2013-07-31T06:04:52.937 回答
2

这是 php 中单例的正常模式。注意 $instance 是一个静态属性,而不是函数中的静态变量。

我无法弄清楚原因,但您的上述代码可以通过执行以下操作之一来修复。

1)去掉Test Function中的引用赋值($Instance =& Singleton::Instance();变成$Instance = Singleton::Instance();

2)去掉Instance Method中的return by reference(public static function &Instance()变成public static function Instance()

3) 或 1 和 2。

class Singleton{
    protected static $instance;

    protected function __construct(){

    }

    protected function __clone(){
        throw new Exception("Cannot clone a Singleton");
    }

    public static function getInstance(){
        if(!isset(static::$instance)){
            static::$instance = new static();
        }
        return static::$instance;
    }
}
于 2013-07-31T05:00:01.513 回答