User defined asertion in PHP
PHP 內建的 assertion 功能已經很強了,但有時候,就是差了這麼一點點,因此,也許我們需要自己做自己的 assertion。
自己做 assertion 怎樣做都可以,反正是自己做。只不過,有些東西還是不一定容易取得,好比說,發生 assertion failure 的 file name、line number。這些東西內建的 assert() 會印,但如果我們要自己做 assertion,那我們就得自己來。
在自己的 assertion function 裡面用 __FILE__、__LINE__ 這類 magic constants 也只會印出實做自己的 assertion function 那一處的檔案及行號,無效。幸好,PHP 裡有個和 Perl 內建的 caller() 功能更強一些的 debug_backtrace()。利用這個函式,我們就可以做自己的 assertion function,用法與內建的 assert() 幾乎一致:
function my_assert($expr)
{
eval('$eval_result__=('.$expr.');');
if (!$eval_result__) {
$bt = debug_backtrace();
printf(
"<b>ASSERTION FAILED</b> @ <a href='javascript://' title='%s' ".
"style='text-decoration: none; '>%s</a>(%d) ",
htmlspecialchars($bt[0]['file']),
basename($bt[0]['file']),
htmlspecialchars($bt[0]['line'])
);
if (count($bt) > 1) {
printf(
" in function <a href='javascript://' title='%s' ".
"style='text-decoration: none; '>%s</a>() ",
htmlspecialchars('function ' . $bt[1]['function'] . '()'),
// @todo Print (file, line) of $bt[1]['function'], too.
htmlspecialchars($bt[1]['function'])
);
}
if (is_string($expr) && ($expr != '')) {
printf('[%s]', htmlspecialchars($expr));
}
printf("<br />\n");
}
}
稍加變化,我們就可以在 assertion failed 時印出指定的訊息:
function my_assert_msg($expr, $msg)
{
eval('$eval_result__=('.$expr.');');
if (!$eval_result__) {
$bt = debug_backtrace();
printf(
"ASSERTION FAILED @ <a href='javascript://' title='%s' style".
"='text-decoration: none;'>%s</a>(%d) ",
htmlspecialchars($bt[0]['file']),
basename($bt[0]['file']),
htmlspecialchars($bt[0]['line'])
);
if (count($bt) > 1) {
printf(
" in function <a href='javascript://' title='%s' ".
"style='text-decoration: none; '>%s</a>() ",
htmlspecialchars('function ' . $bt[1]['function'] . '()'),
// @todo Print (file, line) of $bt[1]['function'], too.
htmlspecialchars($bt[1]['function'])
);
}
if (is_string($expr) && ($expr != '')) {
printf('[%s]', htmlspecialchars($expr));
}
printf(": %s<br />\n", htmlspecialchars($msg));
}
}
改一下 $msg 的處理方式,甚至可以把指定訊息 email 出去給 admin。這樣多幾個參數的複合型 assertion,是原本內建的 assert() 所做不到的。
Post a Comment