在PHP中返回对象的引用

时间:2010-10-18 22:22:18

标签: php reference object pear logging

我正在使用PHP 5.2.14和PearLog 1.12.3。 来自singleton method in Log.php(PEARLog)的最新文档指出:

  

你必须用这个方法调用这个方法   $ var =& Log :: singleton()语法。   没有前面的&符号(&)   方法名称,你不会得到一个   参考;你会得到一份副本。

但是,这样做会产生以下警告:

  

严格通知:只有变量应该   通过引用分配


此功能的来源是:

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计算结果为真。


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

3 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:4)

警告是正确的,API文档已过时,自PHP5起,对象将通过引用返回。

答案 2 :(得分:3)

在PHP 5中,处理引用的方式在PHP中有所改变。现在,他们希望被调用函数决定通过引用或值返回,而不是调用者。 但通常PHP可以自行排序 - 就像在你的情况下它确实检测到这两个是同一个对象。

有关您的E_STRICT的更多信息,请查看手册:http://www.php.net/manual/en/language.references.whatdo.php以及如何实施pear函数: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;这可能导致代码非常不可预测。