2010-10-18 20 views
2

J'utilise PHP 5.2.14 et PearLog 1.12.3. La dernière documentation du singleton method in Log.php (PEARLog) déclare:Retour d'une référence à un objet en PHP

Vous devez appeler cette méthode avec la $ var = & Log :: syntaxe singleton(). Sans l'esperluette (&) devant le le nom de la méthode, vous n'obtiendrez pas de référence ; vous obtiendrez une copie.

Cependant, cela génère donc l'avertissement suivant:

AVIS STRICT: Seules les variables doivent être affectées par référence


La source de cette fonction est:

public static function singleton($handler, $name = '', $ident = '', 
           $conf = array(), $level = PEAR_LOG_DEBUG) 
{ 
    static $instances; 
    if (!isset($instances)) $instances = array(); 

    $signature = serialize(array($handler, $name, $ident, $conf, $level)); 
    if (!isset($instances[$signature])) { 
     $instances[$signature] = Log::factory($handler, $name, $ident, 
               $conf, $level); 
    } 

    return $instances[$signature]; 
} 

Si je retire la & et utiliser simplement:

$var = Log::singleton() 

alors je ne reçois l'avertissement. En outre, si je le fais

$var = Log::singleton(); 
$var2 = Log::singleton(); 

alors $ var === var2 évalue à vrai.


Question: Quelle est correcte: la documentation de l'API ou l'avertissement? (Si la fonction retourne un objet, n'est-ce pas une référence?) Pourquoi ai-je besoin de l'esperluette

+0

Peut-être que c'est écrit pour la compatibilité là-bas. Donc, si vous avez PHP4, ça ira et si vous avez PHP5 ça ira aussi. – Eugene

+1

Ce n'est pas la documentation officielle pour le paquet PEAR_Log qui est lié à http://pear.php.net/package/Log/docs et est disponible à http://www.indelible.org/php/Log/guide .html. La documentation n'indique pas que vous devez utiliser le modèle singleton pour obtenir un objet Log. – kguest

+0

@kguest: le lien que j'ai fourni est le premier que j'ai trouvé, mais ce n'est pas pertinent. La citation provient du code source réel. Ne peut pas être plus autoritaire que cela. Et ma question ne concerne pas l'utilisation du pattern singleton, mais la documentation de la méthode singleton de Log. – JRL

Répondre

10

La manière dont les objets sont passés a fondamentalement changé en PHP5.En PHP4, ils étaient toujours passés en valeur, ce qui signifiait qu'une fonction ou une méthode qui renvoyait un objet transmettait une copie de l'objet. Cela a conduit à l'utilisation de l'opérateur '&', forçant la fonction à renvoyer un objet par référence. En PHP5, les objets sont toujours passés par référence. Pour créer une copie d'un objet, vous devez utiliser l'opérateur clone. D'après un examen très rapide de la source du paquet de log, il semble qu'il reste compatible avec PHP4. Je ne pense pas que vous ayez besoin de l'esperluette. PHP5 renverra une référence à l'objet. Votre test de '$ var === $ var2' a prouvé que la méthode renvoie un objet et que l'objet est une référence à un objet. Si elles étaient des copies d'un objet, la comparaison d'identité serait fausse.

3

La façon de traiter les références a changé un peu en PHP en PHP 5. Maintenant, ils veulent que la fonction appelée décide Mais habituellement, PHP peut résoudre ce problème par lui-même - comme dans votre cas, il détecte que ces deux-là sont le même objet

Pour plus d'informations sur votre commande E_STRICT le manuel: http://www.php.net/manual/en/language.references.whatdo.php et comment la fonction de poire devrait être mise en œuvre: http://www.php.net/manual/en/language.references.return.php. (Dans mon oppinion la plupart des parties de poire sont dépassées, le cadre de zend couvre la plupart de la poire maintenant.)

Edit: Grand exemple de références:

error_reporting(E_STRICT); 
ini_set('display_errors', 1); 

class Settings 
{ 
    private static $_instance; 

    public static function getInstance() 
    { 
     if(self::$_instance == null) 
     { 
      self::$_instance = new Settings(); 
     } 

     return self::$_instance; 
    } 

    public static function &getInstanceByRef() 
    { 
     if(self::$_instance == null) 
     { 
      self::$_instance = new Settings(); 
     } 

     return self::$_instance; 
    } 

    private $counter = 0; 

    private function Settings() 
    { 
    } 

    public function getCounter() 
    { 
     return $this->counter; 
    } 

    public function setCounter($value) 
    { 
     $this->counter = $value; 
    } 
} 

$settings1 = Settings::getInstance(); 
$settings2 = Settings::getInstance(); 

echo $settings1->getCounter(); // 0 
echo $settings2->getCounter(); // 0 

$settings1->setCounter(42); 

echo $settings1->getCounter(); // 42 
echo $settings2->getCounter(); // 42 

$settings3 = &Settings::getInstanceByRef(); // ref to private static $_instance ! 
$settings4 = &Settings::getInstanceByRef(); // ref to private static $_instance ! 

echo $settings3->getCounter(); // 42 
echo $settings4->getCounter(); // 42 

$settings3 = 5; 
$settings5 = Settings::getInstance(); 
echo $settings5; // 5 

Comme vous pouvez le voir même sans refence getInstance est traitée comme référence. Si vous souhaitez utiliser des références, l'appelant et la fonction appelée doivent être marqués comme référence.

En guise d'avertissement: le retour par référence peut causer des bogues difficiles à trouver: Renvoyer par référence me permet d'écraser l'instance privée contenant var. Le comportement attendu dans PHP serait que $ settings3 soit 5 mais pas le static $ _instance privé; Cela peut entraîner un code très imprévisible.

+0

Ainsi, 'Log :: singleton()' retournera-t-il toujours le même objet dans PHP 5 même si la fonction n'est pas déclarée pour renvoyer une référence? – JRL

+0

J'ai ajouté un exemple à ma réponse. Fondamentalement oui - c'est le cas. Voir la réponse de @Jeremy pour plus de détails :) – Fge

4

L'avertissement est correct et la documentation API est obsolète, les objets sont renvoyés par référence depuis PHP5.