2010-10-18 63 views
2

我使用PHP 5.2.14和PearLog 1.12.3。 从singleton method in Log.php(PEARLog)最新文档指出:在PHP中返回对象的引用

则必须调用此方法与 是$ var = &登录::单()的语法。 在 之前没有&符号(&)的方法名称,您将不会得到 引用;你会得到一份副本。

然而,这样做会产生以下的警告:

严格注意:只有变量应该 通过引用


源用于该功能被分配是:

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

如果我删除&,只需使用:

$var = Log::singleton() 

然后我不再得到警告。另外,如果我做

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

然后$ var === var2的计算结果为true。


问题:哪个是正确的:API文档或警告? (如果函数返回一个对象,是不是它是一个参考?为什么我需要&符号?

+0

也许它是为兼容性而编写的。所以,如果你有PHP4,它将是okey,如果你有PHP5,它也可以。 – Eugene 2010-10-18 22:25:09

+1

这不是从http://pear.php.net/package/Log/docs链接到的PEAR_Log软件包的授权文档,可在http://www.indelible.org/php/Log/guide html的。该文档没有说明您必须使用单例模式来获取Log对象。 – kguest 2010-10-19 08:36:05

+0

@kguest:我提供的链接是我发现的第一个链接,但这没什么关系。引用来自实际的源代码。不能比这更具权威性。我的问题不是关于使用单例模式,而是关于Log的单例方法的文档。 – JRL 2010-10-19 13:31:57

回答

10

对象传递的方式在PHP5中基本上发生了变化。在PHP4中,它们总是按值传递,这意味着返回对象的函数或方法实际上是传回对象的副本。这导致使用'&'运算符,强制函数通过引用返回对象。在PHP5中,对象总是通过引用传递。要创建对象的副本,您必须使用克隆操作符。

通过查看日志包的源代码,可以看出它保持与PHP4的兼容性。我不认为你需要符号。 PHP5将返回对该对象的引用。您对'$ var === $ var2'的测试已经证明该方法返回一个对象,并且该对象是对一个对象的引用。如果它们是对象的副本,则身份比较将评估为假。

3

在PHP 5中处理引用的方式在PHP中有所改变。现在他们想要被调用的函数来决定 但通常PHP可以自行排序 - 就像你的情况一样,它检测到这两个是同一个对象。

有关E_STRICT检出的更多信息手册:http://www.php.net/manual/en/language.references.whatdo.php以及如何实现梨功能:http://www.php.net/manual/en/language.references.return.php(在我的看法中,大部分梨是过时的,zend框架现在覆盖大部分梨。)

编辑:引用大量实例:

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 

正如你可以看到,即使没有refence的getInstance作为参考来处理。如果要使用引用,则调用者和被调用函数都必须标记为引用。

作为警告:通过引用返回可能导致很难找到错误:通过引用返回允许我覆盖保存var的私有实例。 PHP中的预期行为是$ settings3是5,但不是私有静态$ _instance;这可能会导致非常不可预知的代码。

+0

即使该函数没有被声明为返回引用,那么'Log :: singleton()'总是会返回PHP 5中的同一个对象吗? – JRL 2010-10-18 23:46:15

+0

我在答案中添加了一个示例。基本上是的 - 它的确如此。有关更多详细信息,请参阅@Jeremy的回答:) – Fge 2010-10-19 01:16:35

4

该警告是正确的,并且API文档已过时,从PHP5开始,通过引用返回对象。