PHP良好編碼方式與技巧注意事項
技術標籤:# PHP實用技術總結
PHP編碼習慣
PHP的命名
function extName($fileName){
$dotPos = strrpos($fileName, '.');
$extName = substr($fileName, $dotPos + 1 );
return $extName;
}
命名的注意事項:
- 命名要有實際含義
- 命名風格保持一致
- 不用拼音命名
- 不用語言關鍵字
適當的使用註釋
終極要求:程式碼就是註釋
- 好的程式碼應該是自描述的
- 難以理解的地方加上註釋
- 函式的功能加上註釋說明
- 類的功能和使用方法加註釋
多備份重要的程式碼
- 程式碼不能只有一份
- 啟用編輯器的自動備份
- 用程式碼管理工具備份
堅持字元編碼統一
PHP檔案編碼 == 模版編碼 == 資料庫編碼
使用之前,變數要初始化
function getInfo($arrId){
$ids = implode(',', $arrId);
$query = mysql_query("select * from test where id in ($ids)");
while($info = mysql_fetch_array($query)){
$info['name'] = trim($info['name']);
$info['addr'] = trim($info['addr']);
$list[] = $info;
}
return $list;
}
function getInfo($arrId){
$list = array();
$ids = implode(',', $arrId);
$query = mysql_query("select * from test where id in ($ids)");
while($info = mysql_fetch_array($query)){
$info['name'] = trim($info['name']);
$info['addr'] = trim($info['addr']);
$list [] = $info;
}
return $list;
}
使用一個未定義的變數, 比使用一個定義好的變數要慢8倍以上!
可以相像, PHP引擎會首先按照正常的邏輯來獲取這個變數, 然而這個變數不存在, 所以
PHP引擎需要丟擲一個NOTICE, 並且進入一段使用未定義變數時應該走的邏輯, 然後返回
一個新的變數.
另外, 閱讀程式碼的角度講, 當你使用一個未定義的變數時, 會讓閱讀你程式碼的人困惑:”這
個變數在那裡初始化的, 和之前的程式碼有關係麼? 和include進來的檔案有關係麼?”
使用 NULL === 來代替 is_null
is_null和 NULL === 完全是一樣的效果, 但是卻節省了一次函式呼叫.
儘量使用 === 儘量不用 ==
PHP有倆組相等比較運算子 === /!== 和 == /!= , == /!= 會有隱式型別轉換,
而 === /!== 會嚴格比較倆個操作時是否型別相同並且值相等.
避免在for迴圈中計算
for($i=0; $i<strlen($str); $i++) {
}
會導致每次迴圈都呼叫strlen, 改為
$j=strlen($str);
for ($i=0; $i<$j; $i++) {
}
strtr替代str_replace
$subject = 'hello, world';
echo strtr($subject, array('hello'=>'world', 'world'=>'hello'));
echo str_replace(['hello'=>'world'], ['world'=>'hello'],$subject);
strtr函式的效率是str_replace的四倍
優先使用單引號
$row[‘id’] 的效率是 $row[id] 的7倍
header頭的編碼
header("Content-type: text/html;charset=utf-8");
php結束標記不要寫
純 PHP 程式碼,最好在檔案末尾刪除 PHP 結束標記
測試環境開啟所有錯誤
error_reporting(7)
- 1:E_ERROR
- 2:E_WARNING
- 4:E_PARSE
但切記,上線之後要關閉我們的報錯,將我們的錯誤程式碼寫入到錯誤日誌中,方便查錯
遮蔽錯誤非常低效
養成不用 @ 的好習慣
$handle = @file('a.txt');
用FALSE表示錯誤, 用NULL表示不存在
對於操作類的函式, 失敗返回FALSE, 表示”操作失敗了”, 而對於查詢類的函式,
如果找不到想要的值, 則應該返回NULL, 表示”找不到”.
優先使用PHP內建函式
正則耗時, 儘量避免, 而採用直接的字串處理函式代替, 如:
filter_var('[email protected]', FILTER_VALIDATE_EMAIL);
有用的PHP內建函式
usort — 使用使用者自定義的比較函式對陣列中的值進行排序
rawurlencode — 按照 RFC 1738 對 URL 進行編碼
parse_url — 解析 URL,返回其組成部分
http_build_query — 生成 URL-encode 之後的請求字元串
exif_imagetype — 判斷一個影象的型別
uniqid — 生成一個唯一ID
get_browser — 獲取瀏覽器具有的功能
str_word_count — 返回字元串中單詞的使用情況
我們php手冊中常見的字串函式和陣列函式,也需要熟悉,優先使用
防禦式程式設計思想
不要相信外部的一切輸入! 所有的輸入都要檢查!
<?php
$username = htmlspecialchars($_GET['username']);
使用PDO操作MySQL
# 寫法一
$sql = "select * from chapter where id=:id";
// 預處理 SQL 語句
$res = $db->prepare($sql);
// 執行 SQL
if ($res->execute([":id" => 1])) {
// 獲取一行結果集
$row = $res->fetch();
print_r($row);
}
# 寫法二
$sql = "select * from chapter where id=? and status=?";
// 預處理 SQL 語句
$res = $db->prepare($sql);
// 執行一條預處理語句
if ($res->execute([2, 1])) {
// 獲取一行結果集
$row = $res->fetch();
print_r($row);
}
PHP的語法糖即語言結構
echo(), print(),die(),isset(),unset(),include(),include_once(),requ
ire(),require_once(),array(),list(),empty(),eval()
echo的逗號和點號
$foo = 'hello';
$bar = 'world';
echo $foo . $bar;
echo $foo , $bar;
逗號優於點號
指令碼執行效率檢測
microtime()對指令碼的執行計時
參考文件:
https://www.php.net/manual/zh/function.error-reporting.php
判斷字串的長度
$str = 'hello';
if (strlen($str) === 5) echo 'do sth...';
if (!isset($str[5])) echo 'do sth..';
strlen()函式函式執行起來相當快,只返回在zval 結構中儲存的已知字串長
度。但是由於strlen()是函式,多多少少會有些慢,isset()是語法糖,因為函式的呼叫會在記憶體裡開闢記憶體空間增加記憶體消耗
使用[]代替array()
$arr = array();
$arr = [];
$arr = array(1,2,3,4);
$arr = [1,2,3,4];
用 … 定義變長引數函式
function addAll(...$num){
$sum = '';
$sum = array_sum($num);
return $sum;
}
addAll(1,2,3,4,5,6,7);
不用eval()
eval() 能夠執行所有的php程式碼,非常的危險!慎用!
//執行當前檔案程式所在目錄
eval('echo `pwd`;');
解決方案:
- 編譯php環境時去除eval()語法糖
- 使用Suhosin保護PHP應用系統
PHP程式碼的優化
if程式碼塊的優化
<?php
if ( 1 == $orderState ) {
$status = 'success';
}else{
$status = 'error';
}
return $status;
#### 完全可以簡化成如下程式碼
//1 先宣告變數賦值,2 判斷是否等於1,是則怎麼樣不是則怎麼樣
$orderState = 'error';
if ( 1 == $orderState ) {
$status = 'success';
}
return $status;
使用三元運算子來替換if
<?php
if ( !empty($_POST['action']) ) {
$action = $_POST['action'];
}else{
$action = 'default';
}
#### 完全可以簡化成如下程式碼
$action = !empty($_POST['action']) ? $_POST['action'] : 'default';
中間結果賦值給變數
<?php
$str = 'this_is_test';
$res = implode('', array_map('ucfirst', explode('_', $str)));
#### 完全可以簡化成如下程式碼
$str = 'this_is_test';
$words = explode('_', $str);
$uWords = array_map('ucfirst', $words);
$res = implode(' ', $uWords);
結果:
使用更加精悍短小的程式碼
- 函式的最佳最大長度是 50-150行程式碼 ,更容易理解也方便修改
- 函式引數 不超過7個
- 只做一件事情的函式更易於複用
PHP的編碼規範
https://github.com/PizzaLiu/PHP-FIG
1、psr-1編碼規範(重要)
https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-1-basic-coding-standard-cn.md
- PHP程式碼檔案必須以 <?php 或 <?= 標籤開始;
- PHP程式碼檔案必須以 不帶BOM的 UTF-8 編碼;
- PHP程式碼中應該只定義類、函式、常量等宣告,或其他會產生 從屬效應 的操作(如:生成檔案輸出以及修改.ini配置檔案等),二者只能選其一;
- 名稱空間以及類必須符合 PSR 的自動載入規範:PSR-4;
- 類的命名必須遵循 StudlyCaps 大寫開頭的駝峰命名規範;
- 類中的常量所有字母都必須大寫,單詞間用下劃線分隔;
- 方法名稱必須符合 camelCase 式的小寫開頭駝峰命名規範。
2、psr-2編碼規範(重要)
https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-2-coding-style-guide-cn.md
- 程式碼必須遵循 PSR-1 中的編碼規範 。
- 程式碼必須使用4個空格符而不是 tab鍵 進行縮排。
- 每行的字元數應該軟性保持在80個之內, 理論上一定不可多於120個, 但一定不能有硬性限制。
- 每個 namespace 名稱空間宣告語句和 use 宣告語句塊後面,必須插入一個空白行。
- 類的開始花括號({)必須寫在其聲明後自成一行,結束花括號(})也必須寫在其主體後自成一行。
- 方法的開始花括號({)必須寫在函式聲明後自成一行,結束花括號(})也必須寫在函式主體後自成一行。
- 類的屬性和方法必須新增訪問修飾符(private、protected 以及 public), abstract 以及 final 必須宣告在訪問修飾符之前,而 static 必須宣告在訪問修飾符之後。
- 控制結構的關鍵字後必須要有一個空格符,而呼叫方法或函式時則一定不能有。
- 控制結構的開始花括號({)必須寫在宣告的同一行,而結束花括號(})必須寫在主體後自成一行。
- 控制結構的開始左括號後和結束右括號前,都一定不能有空格符。
以下例子程式簡單地展示了以上大部分規範:
<?php
namespace Vendor\Package;
use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class Foo extends Bar implements FooInterface
{
public function sampleFunction($a, $b = null)
{
if ($a === $b) {
bar();
} elseif ($a > $b) {
$foo->bar($arg1);
} else {
BazClass::bar($arg2, $arg3);
}
}
final public static function bar()
{
// method body
}
}
3、psr-3編碼規範-定義日誌規範(重要)
https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-3-logger-interface-cn.md
4、psr-4名稱空間編碼規範(重要)
https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md