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

San*_*lin 4 php singleton static reference function

我已经注意到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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并具有以下功能:

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

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

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

    return $Instance;
}
Run Code Online (Sandbox Code Playgroud)

当我使用以下内容时:

Test(TRUE);
Test();
Singleton::Instance();
Run Code Online (Sandbox Code Playgroud)

输出是:

Class Echo
NULL
Function Echo
object(Singleton)#1 (0) {
}
Function Echo
NULL
Class Echo
object(Singleton)#1 (0) {
}
Run Code Online (Sandbox Code Playgroud)

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

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

Ja͢*_*͢ck 6

这种行为被记录:

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

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

$Instance = Singleton::Instance();
Run Code Online (Sandbox Code Playgroud)

更新

我简化了以下问题:

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

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

  var_dump($test);
}

$v = 1;

test2(true, $v);
test2();
Run Code Online (Sandbox Code Playgroud)

输出:

int(1)
NULL
Run Code Online (Sandbox Code Playgroud)