2009-12-22 37 views
4

設法在對象上創建一個新的屬性。但是,有人可以用支持鏈接來解釋爲什麼setAttrib有兩種不同的表現方式嗎?爲什麼它不會導致......等待它......堆棧溢出!! ??PHP:__set函數行爲每次都不相同

class Test 
{ 
    public function setAttrib($key, $value) { 
    echo "setAttrib\n"; 

    // first time: calls $this->__set($key, $value) 
    // second time: just sets a public property (but, when exactly was it created?) 
    $this->$key = $value; 
    } 

    public function __set($key, $value) { 
    echo "__set\n"; 
    $this->setAttrib($key, $value); 
    } 
} 

$test = new Test(); 
$test->setAttrib('hey', 'It works'); 
var_dump($test); 

產生...

setAttrib 
__set 
setAttrib 
object(Test)#1 (1) { 
    ["hey"]=> 
    string(8) "It works" 
} 

編輯:我不是在尋找一種替代。 我正在尋找這個工程的原因。

+0

不知道它是否會改變任何東西,但你的__set方法應該是公開的(參見http://www.php.net/manual/en/language.oop5.overloading.php,其中指出「所有重載方法必須定義爲公共。「 - 以及在運行代碼時得到的警告) – 2009-12-22 20:24:14

+0

是的,你就在那裏,我將它改爲公開。同樣的行爲。 – 2009-12-22 20:28:16

+1

至少,這是一個警告,沒有更多的^^(我沒想到它會別人改變什麼,這就是爲什麼我只發佈的評論;但一個警告了總是一件好事) – 2009-12-22 20:35:25

回答

8

你不是唯一一個誰似乎有通知,非遞歸行爲:this comment on the manual's page狀態:

2 - PHP不會遞歸從內部本身(調用一個 魔術方法在 至少在相同的$name)。

而且,有點後來在同一頁上,有this one,其中規定:使用 __set

遞歸檢測功能可以 證明特別危險。當PHP遇到一個 聲明,通常會叫 __set但會導致遞歸, 而不是發射了警告或 根本就沒有執行,就好像有根本沒有定義__set 方法它 將採取行動的說法。
在這種情況下,默認 行爲是 動態指定的屬性 增加從而打破所有進一步 呼叫的 期望的功能到__set__get爲該 屬性的對象。


而且,在PHP的錯誤追蹤系統,有#47215 : magic method __set() is bypassed on recursive call,它說:

魔術方法__set()上 遞歸調用繞過。
PHP自動 創建的遞歸調用__set()或 而不是拋出一個遞歸性 錯誤

它已被封閉,而不是 在實例屬性:

感謝您抽出寶貴時間寫 給我們,但這不是一個錯誤。

這個bug報告,本身指向this blog-post,從而結束這個句子(引用,重點煤礦)

畢竟我覺得這可能不是一個問題 但預期行爲,否則我們 不能從__set() 方法內定義對象 屬性。

+0

對我而言,PHP正在詛咒地調用__set(),這使我瘋狂,我無法動態地定義屬性並在同一個類中擁有魔法__set。我正在使用PHP 5.3.2。他們改變了這種行爲嗎,還是我誤解了? – 2014-09-17 16:02:03

2

__set僅在寫入不可訪問的屬性時才使用。也就是說,那些無法訪問(私人或受保護)或者根本沒有設置的人。因此,__set只會被調用一次。

這裏發生了什麼:

  • setAttrib:嘗試寫入
  • 類:無法訪問屬性
  • __set:做任何__set被告知這樣做,這是再次調用setAttrib。
  • setAttrib:嘗試寫
  • class:無法訪問的屬性,但__set無法遞歸,並且我們已經在其中,因此如果__set不存在,那麼就這樣做。

查看用戶對http://php.net/__set的評論用於證明__set無法遞歸。

+0

我想知道, '嘿'成員是什麼時候創建的?這裏不僅僅是滿足眼睛。 – 2009-12-22 20:24:55

+0

它寫在setAttrib的最後一次運行中。 – 2009-12-22 20:25:34

+0

它發生在你第一次調用set屬性時。 '__set'永遠不會捕獲它,除非你執行'$ a = new MyClass(); $ a-> hey ='我的文本';'在不能訪問'MyClass :: $ hey'的類中。 – prodigitalson 2009-12-22 20:29:19

0

__set__get只有在該成員受到保護時纔會接收該屬性的調用。意思是在對象$this->$key內設置屬性$key。如果從超出範圍調用,則調用__set邏輯。你的一個調用發生在對象之外的對象中。

相關問題