A function estática dentro da variável não pode fazer referência a singleton

Eu notei um comportamento estranho com singletons no PHP, não há melhor maneira de explicar isso, mas com um exemplo.

Digamos que eu tenho a seguinte class singleton:

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; } } 

E a seguinte function:

 function Test($Init = FALSE) { static $Instance; if ($Init === TRUE && !isset($Instance)) { $Instance =& Singleton::Instance(); } echo 'Function Echo'.PHP_EOL; var_dump($Instance); return $Instance; } 

E quando eu uso o seguinte:

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

A saída é:

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

Como você pode ver, a referência salva dentro da function é perdida após a execução mesmo que a variável esteja estática. Observe também que a variável estática dentro do método da class está funcionando bem.

Isso é suposto ser normal ou estou fazendo algo errado?

Esse comportamento está documentado :

O Zend Engine 1, que conduz o PHP 4, implementa o modificador estático e global para variables ​​em termos de referências . Por exemplo, uma variável global verdadeira importada dentro de um escopo de function com a declaração global realmente cria uma referência para a variável global. Isso pode levar a um comportamento inesperado.

Esse comportamento não mudou desde ZE1 e a solução é simplesmente não atribuir uma referência a uma variável estática, então:

 $Instance = Singleton::Instance(); 

Atualizar

Simplifiquei o problema abaixo:

 function test2($init = false, $value = null) { static $test; if ($init) { $test =& $value; } var_dump($test); } $v = 1; test2(true, $v); test2(); 

Saída:

 int(1) NULL 

Este é o padrão normal para um singleton em php. Observe que a instância $ é uma propriedade estática não uma variável estática dentro de uma function.

Estou tendo problemas para descobrir por que, mas o seu código acima pode ser corrigido, fazendo um dos seguintes.

1) Remova a atribuição de referência na function de teste ( $Instance =& Singleton::Instance(); torna-se $Instance = Singleton::Instance(); )

2) Remova o retorno por referência no Método da Instância ( public static function &Instance() torna-se public static function Instance() )

3) Ou ambos 1 e 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; } }