PHP Coding Standard and 50+ Programming SkillsHo Kim
1. How and Why to write good code?
2. Coding standard based on ZendFramework and real world practise.
3. PHP programming skills from daily coding.
4. Some security tips
5. Some optimization tips
5. E_ERROR
• 產生以下錯誤
Fatal error: Uncaught Error: Call to undefined function bar() in
D:wwwslimpublicindex.php:7
• 因為 function 根本不存在,系統無從猜測可能的行為,也無法修復錯誤,故為
Fatal Error,強制停止程式運作。
function foo() {
echo 'foo';
}
bar(); // 呼叫了不存在的 function
6. E_WARNING
• 產生以下錯誤畫面:
Warning: A non-numeric value encountered in D:wwwslimpublicindex.php on line 3
123
• 不正確的資料操作與計算,可能造成程式 BUG,但是系統可以修復其行為,所以
程式不會中斷,可以被隱藏。
$result = 123 + 'ABC'; // 數字加字串
echo sprintf('<span style="color: red;">%s</span>', $result);
7. E_NOTICE
• 產生以下畫面
Notice: Undefined variable: b in D:wwwslimpublicindex.php on line 6
A
• $b 沒有被預先宣告,這種寫法在 PHP 中是允許的,但是這樣子有很大機率出現
BUG ,故 PHP 會用 Notice 提示你最好預先宣告。
$a = 'A';
$ab = $a . $b; // $b 不存在
echo $ab;
8. E_STRICT
• 產生以下錯誤訊息
Warning: Declaration of B::foo() should be compatible with A::foo($a = 123)
in D:wwwslimpublicindex.php on line 17
對PHP開發過程更嚴謹的要求。
class A {
public function foo($a = 123)
{
}
}
class B extends A
{
// 與 parent class 介面不一樣
public function foo()
{
}
}
9. E_DEPRECATED
• 產生以下畫面
Deprecated: Function mcrypt_create_iv() is deprecated
in D:wwwslimpublicindex.php on line 6
�Ի��eD��IN�
• 若使用了已被棄用的語言功能就會發出此提示,提醒你趕快改用新功能。
error_reporting(E_ALL);
// PHP 7.2 deprecated mcrypt
$v = mcrypt_create_iv(16);
echo $v;
10. 你也可以產生屬於自己的錯誤訊息
• 用 trigger_error() 來立即觸發使用者定義的錯誤訊息
• 預設值是 E_USER_NOTICE,所以程式會繼續執行下去,只是跳 Notice 訊息。
Notice: $a is not A in D:wwwslimpublicindex.php on line 6
B
$a = 'B';
if ($a !== 'A') {
trigger_error('$a is not A', E_USER_NOTICE);
}
echo $a;
11. 改用 E_USER_ERROR
• 這次用的是 ERROR type,程式就會終止執行了:
Fatal error: $a is not A in D:wwwslimpublicindex.php on line 6
• 可用的種類有:
E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING, E_USER_DEPRECATED 等
大多數 E_* 的錯誤訊息,都有 E_USER_* 的對應
if ($a !== 'A') {
trigger_error('$a is not A', E_USER_ERROR);
}
35. Exception 可以無視層次跳躍
• 範例中 Exception 是在 function 內拋出,但是外部的 try ... catch 可以抓到。
• Exception 是無視層次的,會向上一直跳到有 try ... catch 的地方才停止。
• 如果沒有 try ... catch,則會跳到最上層,成為 Fatal Error 終止程序。
function foo($a) {
if ($a !== 'A') {
throw new RuntimeException('$a is not A');
}
echo $a;
}
try {
foo('B');
} catch (RuntimeException $e) {
echo $e->getMessage();
}
36. 沒有捕獲 Exception 的結果
• 會顯示 Uncaught Exception 然後終止程序
Fatal error: Uncaught RuntimeException: $a is not A in D:wwwslimpublicindex.php:5
Stack trace: #0 D:wwwslimpublicindex.php(11): foo('B') #1 {main} thrown
in D:wwwslimpublicindex.php on line 5
function foo($a) {
if ($a !== 'A') {
throw new RuntimeException('$a is not A');
}
echo $a;
}
foo('B');
46. 不要這樣用
• 如果你只是想讓未登入 user 轉過去登入頁面,在這個案例中,用 if 就能處理了
try {
if ($user->group === 'guest') {
throw new UnauthorisedException('Please login', 401);
} elseif (...) {
} elseif (...) {
} else {
}
} catch (UnauthorisedException $e) {
header('Location: /login');
}
if ($user->group === 'guest') {
header('Location: /login');
}
47. 但可以這樣用
• 這個案例中,user group 如果出現預定義的格式以外的值,肯定屬於異常狀況,就
直接拋出 Exception 吧。
switch ($user->group) {
case 'guest':
// Please login first.
case 'member':
// Welcome Back
case 'manager':
// Sir, yes sir.
default:
throw new UnauthorisedException('Uh... Who are you?', 403);
}
50. 使用 Exception 的情境
• 通常比較少在同一個空間內同時 try ... catch 又同時 throw Exception。
• 開發 function 的人可以根據異常狀況拋出各種 Exception,幫助使用 function 的人
處理例外流程。
• 使用 function 的人可以用 try ... catch 捕獲 function 的異常,然後處理可能的錯誤
修復。
• 是否是【異常】非常重要,既定的可預期流程,都應該用 if else 處理。但是異常
的處理可以放心用 Exception 作流程跳轉。
51. 防禦型程式設計
public function __construct($string, $int, $array)
{
// 最基本的檢查,型別不對就丟錯
if (!is_string($string))
{
throw new InvalidArgumentException('Argument 1 should be string.');
}
// 這個檢查比較鬆一點,只要是數字都可以過,不一定要 int 型態
if (!is_numeric($int))
{
throw new InvalidArgumentException('Argument 2 should be a number.');
}
// 這個檢查比較特別,如果是 Iterator 物件也能夠接受,因為同樣可以 foreach
if (!is_array($array) && !($array instanceof Traversable))
{
throw new InvalidArgumentException('Argument 3 should be Traversable.');
}
// Do some stuff
}