2013-03-19 36 views
13

當我運行「Behat」步驟時,Behat error handler將「嘗試獲取非對象的屬性」錯誤轉爲異常。PHP轉「調用非對象的成員函數」爲例外

這非常有幫助,因爲它會導致該步驟被標記爲失敗,並允許測試運行在下一個場景中繼續。

但是,「調用非對象成員函數」錯誤是致命的,並立即停止測試執行(包括中止將結果寫入xml)。這是無益的。

我的問題是:

  1. 是什麼這兩個錯誤之間的區別?他們是不同的「錯誤級別」?記錄在哪裏?我已經搜索了PHP站點和Google,並且找不到規範的參考資料,只是有很多關於調試每個錯誤的特定實例的問題。

  2. 有什麼辦法可以將後面的錯誤轉換成異常,而不是完全停止腳本?在我看來,取消引用「null」和「->」將是一個錯誤,「無法從諸如內存分配問題中恢復」。

更新:

看起來這僅僅是一個已知的問題用PHP。請參閱:

  • #51882呼叫要對非對象成員函數應該拋出一個異常
  • #46601 E_RECOVERABLE_ERROR爲「調用一個成員函數的非對象」
  • #51848非對象方法調用錯誤應該是開捕帶的set_error_han dler()
  • #63538「調用未定義功能」應該是開捕

了一些p-人們說這是「按設計」,但我認爲這只是在將對象添加到PHP之前定義的錯誤級別的人造物。用非OO語言調用一個不存在的函數是一個嚴重的錯誤,我可以看到它是如何被描述爲「致命的」或「不可恢復的」(儘管在非OO語言中可以定義函數即使這似乎過分悲觀)。現在,現在您可以在任何舊的$a上執行「$a->f()」,但「f」可能不存在的可能性更大,並且它看起來應該不是致命錯誤(參見Java,其中這將是NullPointerException )。

我想,讓我到一個新的問題:

_ 3.你怎麼能修補PHP使「調用一個成員函數的非對象上」錯誤非致命性,而不會大規模破向後兼容,以及您可以採取哪些步驟來最大限度地將該補丁程序接受到PHP中?

更新2重新修補PHP:

有進行這種修復一些有限的支持on the PHP internals mailing list。現在我只需要編寫一個修補程序來解決這個問題並創建一個RFC。

回答

4

問題是你可以聲明一個對象的屬性爲動態的,但是你不能聲明一個動態的方法。 因此,如果您嘗試在非對象上調用方法,則會發生致命錯誤,因爲PHP無法確定該函數是否存在。

檢查this codepad對於一些簡單的輸出與錯誤號碼。

現在仔細看一下關於「設置和訪問未設置屬性」的部分。你可以看到PHP給你一條消息:「從空值創建默認對象」。所以如果一個類不存在,PHP會爲你創建它。使用類型轉換時會發生同樣的情況,請參閱object typecasting

因此,您可以訪問非對象的參數,因爲它會在動態創建的默認對象中檢查該參數。但是如果你訪問一個方法,那個默認對象仍然沒有那個方法。

這就是爲什麼一個屬性返回一個8級錯誤和一個方法1級錯誤(見error levels)。 由於它返回1級致命錯誤,因此在此過程後無法繼續。

+0

謝謝;這解釋了差異背後的一些想法。你有沒有引用缺少的方法是1級,而缺失的屬性是8級,還是隻能通過實驗來確定? – Rich 2013-03-19 16:52:51

0

我對你有一些好消息:有一個名爲Error Exceptions的PHP庫,它將所有的PHP錯誤轉化爲可捕獲的異常。

這是一個相當戲劇性的變化,事情的方式,但顯然你不是唯一一個誰想要做到這一點。這個庫是由Anthony Ferrara編寫的,他是PHP核心開發人員之一,所以你可以相當肯定他知道他在做什麼,但如果你想自己做,它會使用set_error_handler() function ;如果你想陷入PHP的錯誤,這是你如何做到這一點。

希望有所幫助。

+1

我還沒有嘗試過,但是這個庫在純PHP中,並且只使用了'set_error_handler'和'register_shutdown_function',所以我確信這隻會做Behat能夠在代碼鏈接我原來的問題。特別是,它不會允許你通過調用'null'值的對象方法來恢復。我認爲您需要修補PHP C運行時才能實現這一點(請參閱我的q的第3部分) – Rich 2013-03-19 17:07:45

相關問題