函数内部的静态变量不能保持对单例的引用

时间:2013-07-31 04:50:32

标签: php function reference static singleton

我注意到在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) {
}

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

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

2 个答案:

答案 0 :(得分:6)

此行为为documented

  

Zend Engine 1,驱动PHP 4,根据static为变量实现globalreferences修饰符。例如,使用全局语句在函数作用域内导入的真实全局变量实际上会创建对全局变量的引用。这可能会导致意外行为。

此行为自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

答案 1 :(得分:2)

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

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

1)删除测试功能中的参考分配($Instance =& Singleton::Instance();变为$Instance = Singleton::Instance();

2)在实例方法中删除引用返回(public static function &Instance()变为public static function Instance()

3)或者1&amp; 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;
    }
}