2010-10-18 99 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開始,通過引用返回對象。