PHP 中的斷言常用於偵錯,檢查一個表達式或語句是否為 FALSE。本文帶你重新認識 PHP assert() 函數的神通廣大。
本文基於PHP Version 7.1.28
一、什麼是斷言
編寫程式時,常會做出一定的假設,那斷言就是用來捕捉假設的異常,我們也可以認為斷言是異常的一種特殊形式。
斷言一般用於程式執行結構的判斷,不可讓斷言處理業務流程。用的最多的場景就是單元測試,一般的單元測試框架都採用了斷言。
assert(1 == 2); // 运行结果: // Warning: assert(): assert(1 == 2) failed in /Users/shocker/Desktop/demo.php on line 25
二、PHP中的斷言
在 PHP 中,採用 assert()函數對表達式進行斷言。
// PHP 5assert ( mixed $assertion [, string $description ] ) : bool // PHP 7assert ( mixed $assertion [, Throwable $exception ] ) : bool
四、傳統的斷言方式
#參數assertion 既支援表達式,也支援表達式字串(某些特定的場景會用到,例如判斷某個字串表達式是否合法)
如果assertion 是字串,它將會被 assert() 當做PHP 程式碼來執行。 assertion 是字串的優點是當停用斷言時它的開銷會更小,並且在斷言失敗時訊息會包含 assertion 表達式。
斷言這個功能應該只會被用來除錯。你應該用於完整性檢查時測試條件是否始終應該為 TRUE,來指示某些程式錯誤,或檢查特定功能的存在(類似擴充函數或特定的系統限制和功能)。
斷言不應該用於普通運行時操作,類似輸入參數的檢查。作為一個經驗法則,在斷言禁用時你的程式碼也應該能夠正確地運行。
實例:
function my_assert_handler($file, $line, $code, $desc){ echo "Assertion Failed: File '{$file}' Line '{$line}' Code '{$code}' Desc '{$desc}' "; } // 设置回调函数 assert_options(ASSERT_CALLBACK, 'my_assert_handler'); // 让一则断言失败 assert('1 == 2', '1 不可能等于 2');
執行結果:
Assertion Failed: File '/Users/shocker/Desktop/demo.php' Line '29' Code '1 == 2' Desc '1 不可能等于 2'
#五、支援異常的斷言
在PHP 7 中,assert() 是一種語言結構,允許在不同環境中生效不同的措施,具體可見 zend.assertions配置。
另外,也支援透過 AssertionError 捕捉錯誤。
使用範例:
assert_options(ASSERT_EXCEPTION, 1); // 在断言失败时产生异常 try { // 用 AssertionError 异常替代普通字符串 assert(true == false, new AssertionError('True is not false!')); } catch (Throwable $e) { echo $e->getMessage(); }
運行結果:
True is not false!
#六、對斷言行為控制
PHP 支援 assert_options()函數對斷言進行配置,也可用ini 進行設定
以下配置中,常數標誌用於 assert_options() 函數進行配置,ini 設定用於 ini_set() 函數設置,效果一樣
#zend.assertions 是特殊的設定(PHP >= 7.0.0 支援),控制不同運作環境下斷言的行為,只可用 ini_set() 設定。並且,設定了1就不能再設定為-1,反之亦然,其他不受限。
1: 編譯程式碼,並執行(開發模式)
0: 編輯程式碼,但執行時間跳過
-1: 不編譯程式碼(生產模式)
七、版本的不相容
PHP >= 5.4.8,description 可作為第四個參數提供給ASSERT_CALLBACK 模式裡的回呼函數
在PHP 5 中,參數assertion 必須是可執行的字串,或是執行結果為布林值的表達式
在PHP 7 中,參數assertion 可以是任意表達式,並用其運算結果作為斷言的依據
在PHP 7 中,參數exception 可以是個 Throwable 對象,用於捕獲表達式運行錯誤或斷言結果為失敗。 (當然 assert.exception 需開啟)
PHP >= 7.0.0,支援 zend.assertions、assert.exception 相關設定及其特性
PHP >= 7.2 版本開始,參數assertion 不再支援字串
Deprecated: assert(): Calling assert() with a string argument is deprecated
八、應用程式場景
#偵錯輸出:
#先看範例:
assert('1 == 2', '1 不可能等于 2');
運行結果:
Warning: assert(): 1 不可能等于 2: "1 == 2" failed in /Users/shocker/Desktop/demo.php on line 10
類似於:
$expression = 1 == 2; if (!($expression)) { echo "1 不可能等于 2\n"; var_dump($expression); echo __FILE__ . "\n"; }
但是,我們無法得知$expression 的具體表達式,也無法得知具體的執行行數。
九、單元測試
function arraySum(array $nums) { $sum = 0; foreach ($nums as $n) { $sum += $n; } return $sum; } assert(arraySum([1, 2, 3]) == 6, 'arraySum() 测试不通过:'); assert(is_numeric(arraySum([1, 2, 3])), 'arraySum() 测试不通过:');
#第十、驗證表達式
Tip:
PHP 7 開始,新增了 Error 類別用於捕捉PHP 內建錯誤,包括語法錯誤。 Error 與先前的 Exception 都繼承自 Throwable,所以從 7.0.0 開始,Throwable 可以捕捉一切錯誤和異常。
下例示範如何驗證某個字串表達式是否為合法的PHP 表達式:
try { assert('a +== 1'); } catch (Throwable $e) { echo $e->getMessage(), "\n"; }
運行結果:
Failure evaluating code: a +== 1
##十一、安全性問題
function demo(){ file_put_contents('data.log', 'shockerli.net'); return true; } $func = $_GET["func"]; assert("$func()");
所以,对于 assert 函数,正常情况下是不建议用于生产环境的。
与 eval 一样会执行任何 PHP 代码,危害极大。这也是 PHP 从 7.2 开始废弃支持字符串表达式的原因
感谢您的阅读,如有错误请指出。
相了解更多相关问题请访问PHP中文网:PHP视频教程
以上是什麼是PHP斷言(assert)?該如何使用?的詳細內容。更多資訊請關注PHP中文網其他相關文章!