我正在使用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文档或警告? (如果函数返回一个对象,不管它是不是参考?为什么我需要&符号?
答案 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;这可能导致代码非常不可预测。