我相信每個公司都有一套完備的程式碼規範標準,但標準是標準,如何能有效的讓所有人遵守,那就要工具的輔助和實時提醒了。
如前端 vue 的大家基本都會使用 eslint
來約束我們的程式碼,一旦多一個空格都會提示你有問題,當 npm run dev
或者 npm run watch
就會提示你哪哪哪不符合規範。
在 Laravel 開發中,照樣也有類似的工具,這也是本文的所要推薦的:phpcs
在開始使用 phpcs
之前,我們簡單來說說 Laravel 的程式碼規範標準
Laravel 程式碼規範
Laravel follows the PSR-2 coding standard and the PSR-4 autoloading standard.
來自 Laravel 的說明:laravel.com/
幾個程式碼規範的含義
- PSR-0 自動載入規範 (已棄用)
- PSR-1 基礎編碼規範
- PSR-2 編碼風格規範
- PSR-3 日誌介面規範
- PSR-4 自動載入規範
- PSR-5 PHPDoc 標準 (未通過)
- PSR-6 快取介面規範
- PSR-7 HTTP 訊息介面規範
- PSR-8 Huggable 介面 (未通過)
- PSR-9 專案安全問題公示 (未通過)
- PSR-10 專案安全上報方法 (未通過)
- PSR-11 容器介面
- PSR-12 編碼規範擴充
- PSR-13 超媒體連結
- PSR-14 事件分發器 (未通過)
- PSR-15 HTTP 請求處理器
- PSR-16 快取介面
其實現在很多網站已經掛出 PSR-2 編碼規範的說明了,推薦看下面這個:
laravel-china.org/docs/psr/ps…
但我在實際使用時,除了能夠按照上面說的規範來,還有一塊重要的內容他們沒提。
檔案和類註釋
主要包含以上內容塊:檔案說明、PHP 版本號、還有就是按順序的這五要素:(category, package, author, license, link),而且這五要素排版要對齊哦,一般人我不告訴哦~~~
方法註釋
主要包含:方法說明、空一行、引數塊 (型別、引數名、含義 —— 這個需要對齊)、空一行、最後 return
型別。
安裝 phpcs
使用 phpcs 之前,還是需要先知道這個東西是什麼吧?
PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.
主要包含兩個工具:phpcs 和 phpcbf (這個之後再說)。phpcs 主要對 PHP
、JavaScript
、CSS
檔案定義了一系列程式碼規範標準,如我們會使用的,也是 Laravel 使用的 PHP
PSR-2
標準,能夠檢測出不符合我們定義的程式碼規範的程式碼,併發出警告和錯誤,當然我們也可以設定報錯的級別。
對於 phpcs 的使用,主要有兩個途徑:
- 在本地開發過程中,實時對我們的程式碼進行檢測,讓程式碼提交版本庫時,就已經符合規範標準了;
- 在伺服器對提交的程式碼進行檢測,如果不符合標準的,則不入程式碼庫,打回要求修改。
下面我們開始說說根據不同方法,如何安裝 phpcs 工具的。
composer
composer global require "squizlabs/php_codesniffer"
複製程式碼
寫 Laravel 程式碼的同學,對使用 composer 應該很熟悉了,這種方法比較推崇。但主要區分為是「全域性安裝」還是按「專案安裝」。
這裡我本人推薦採用「全域性安裝」,可以在各個 IDE 上直接填入全域性安裝的 phpcs 可執行路徑。但如果你的版本庫是使用「git」的話,那我推薦使用「專案安裝」,下文就知道原因了。
注: 我使用這種方式「全域性安裝」後,發現每回都關聯不了「VSCode」,這個原因待查。
pear
安裝 pear
curl -O https://pear.php.net/go-pear.phar
php -d detect_unicode=0 go-pear.phar
複製程式碼
開始安裝配置,
先選擇 1 (change the Installation Base);
輸入:
/usr/local/pear
,再選擇 4 (change the Binaries directory),
輸入:
/usr/local/bin
開始安裝 PHP_CodeSniffer
pear install PHP_CodeSniffer
複製程式碼
在 MacOS 系統下:
在 Centos Linux 系統下安裝效果:
此方法比較有效果,而且也符合在多系統上嘗試,比如本人同時在「Mac」和 「Linux」下都可以正常安裝和使用。
*注:*我沒在「Windows」環境下嘗試,尚未知道效果。
brew
brew install php-code-sniffer
複製程式碼
這種方法顯然在「Mac」系統下有效了!
當然根據官網的文件,還有其他方法,歡迎大家去嘗試:
具體可參考:github.com/squizlabs/P… 中的「Installation」部分。
使用 phpcs
無論是本地還是伺服器,只要我們安裝好了,自然就可以開始使用了。最直觀也是最簡單的方法莫過於用命令列的方式了,如:
phpcs php_path
// or
phpcs php_dir
複製程式碼
但想到我們是用 IDE 寫程式碼的,而且是希望實時看到效果的,所以下面嘗試在幾個 IDE 下看看如何使用。
安裝 VSCode 外掛
在外掛介面,搜尋:phpcs,安裝即可。
配置外掛
由於專案使用的是系統的 phpcs,所以需要在 user setting
中配置可執行路徑和自己自定義的編寫風格
這時候我們去看看我們的程式碼介面,是不是有了 phpcs
的提示了:
![2018-05-10 09.29.08](http://ow20g4tgj.bkt.clouddn.com/2018-05-10-2018-05-10 09.29.08.gif)
安裝 PhpStorm 外掛
直接看圖,不需要做過多的說明了。
基本到此,phpcs 的外掛就可以使用了。
版本檢測規範
我們希望在團隊專案程式碼提交版本庫之前「pre-commit」就能檢測 出不符合「PSR-2」 標準的程式碼檔案。無論是 svn 或者 git,都能在「pre-commit」獲取提交版本庫的程式碼檔案,然後再利用「phpcs」去檢測每個檔案是否符合規範。
svn
由於每個 svn 在服務端都有對應 hooks 資料夾,可以在「pre-commit」時,驗證程式碼的規範,直接上檔案,比較好理解:
#!/bin/bash
LOG="/tmp/svn.log"
touch ${LOG}
REPOS="$1"
TXN="$2"
echo "REPOS: $REPOS" > ${LOG}
echo "TXN: $TXN" >> ${LOG}
SVNLOOK="/usr/bin/svnlook"
PHPCS="/usr/bin/phpcs"
# php file extension
PHP_EXT="php"
MSG_MIN_CHAR_NUM=3
MAX_PNG_SIZE=2048
PROHIBITED_FILES=(
)
TMP_DIR="/tmp/svn"
if [[ -d ${TMP_DIR} ]]; then
rm -r ${TMP_DIR}
fi
mkdir -p ${TMP_DIR}
function check_php_syntax {
local php_file=$1
echo `${PHPCS} ${php_file} 2>&1`
}
function create_file {
local file_name=$1
# Create tmp file and copy content
tmp_file="${TMP_DIR}/${file_name}"
mkdir -p "$(dirname "${tmp_file}")" && touch "${tmp_file}"
${SVNLOOK} cat -t "${TXN}" "${REPOS}" "${file_name}" > ${tmp_file}
}
changed_info_str=`${SVNLOOK} changed -t "${TXN}" "${REPOS}"`
IFS=$'\n' read -rd '' -a changed_infos <<<"${changed_info_str}"
php_error_msg=""
for changed_info in "${changed_infos[@]}"; do
# Prevent commiting file that contains space in its filename
echo ${changed_info} >> ${LOG}
operation=`echo ${changed_info} | awk '{print $1}'`
if [[ ${operation} = "A" ]] && [[ `echo ${changed_info} | awk '{print NF}'` -gt 2 ]]; then
echo "Please do not commit file that contains space in its filename!" 1>&2
exit 1
fi
file_name=`echo ${changed_info} | awk '{print $2}'`
echo "operation: ${operation}, file: ${file_name}, ext: ${ext}" >> ${LOG}
# Check prohibit-commit files
for prohibited_file in ${PROHIBITED_FILES[@]}; do
if [[ ${file_name} = ${prohibited_file} ]]; then
echo "${file_name} is not allowed to be changed!" 1>&2
exit 1
fi
done
ext=`echo ${file_name} | awk -F"." '{print $NF}'`
if [[ ${operation} = "U" ]] || [[ ${operation} = "A" ]]; then
tmp_file="${TMP_DIR}/${file_name}"
# Check lua syntax
if [[ ${ext} = ${PHP_EXT} ]]; then
echo "Check syntax of ${tmp_file}" >> ${LOG}
create_file ${file_name}
error_msg=`check_php_syntax ${tmp_file}`
if [[ `echo ${error_msg} | sed 's/\n//g'` != "" ]]; then
php_error_msg="${php_error_msg}\n${error_msg}"
fi
fi
fi
done
rm -r ${TMP_DIR}
if [[ ${php_error_msg} != "" ]]; then
echo "php error: ${php_error_msg}" >> ${LOG}
echo "Please fix the error in your php program:${php_error_msg}" 1>&2
exit 1
fi
exit 0
複製程式碼
這就是我們想要看到的效果了,無論 IDE 的實時提示,還是提交程式碼時的檢測反饋,都會告訴我們哪裡格式不符合規範了。
git
這裡主要參考 WickedReports/phpcs-pre-commit-hook github.com/WickedRepor… 的寫法:
#!/bin/sh
PROJECT=`php -r "echo dirname(dirname(dirname(realpath('$0'))));"`
STAGED_FILES_CMD=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`
# Determine if a file list is passed
if [ "$#" -eq 1 ]
then
oIFS=$IFS
IFS='
'
SFILES="$1"
IFS=$oIFS
fi
SFILES=${SFILES:-$STAGED_FILES_CMD}
echo "Checking PHP Lint..."
for FILE in $SFILES
do
php -l -d display_errors=0 $PROJECT/$FILE
if [ $? != 0 ]
then
echo "Fix the error before commit."
exit 1
fi
FILES="$FILES $PROJECT/$FILE"
done
if [ "$FILES" != "" ]
then
echo "Running Code Sniffer. Code standard PSR2."
/usr/local/bin/phpcs --standard=PSR2 --colors --encoding=utf-8 -n -p $FILES
if [ $? != 0 ]
then
echo "Fix the error before commit!"
echo "Run"
echo " ./vendor/bin/phpcbf --standard=PSR2 $FILES"
echo "for automatic fix or fix it manually."
exit 1
fi
fi
exit $?
複製程式碼
我們把該檔案內容寫入「.git/hooks/pre-commit」中,然後再提交一個檔案,看看執行效果。
在實驗之前,我們先呼叫本地的 phpcs
外掛,看看我們的一個檔案程式碼的規範情況:
phpcs --standard=PSR2 --encoding=utf-8 -n -p app/Http/Controllers/ApplyController.php
複製程式碼
執行結果提示:
E 1 / 1 (100%)
FILE: /Users/app/Http/Controllers/ApplyController.php
------------------------------------------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 3 LINES
------------------------------------------------------------------------------------------------------
17 | ERROR | [x] Opening brace should be on a new line
60 | ERROR | [x] Opening parenthesis of a multi-line function call must be the last content on the
| | line
62 | ERROR | [x] Multi-line function call not indented correctly; expected 12 spaces but found 16
62 | ERROR | [x] Closing parenthesis of a multi-line function call must be on a line by itself
------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 4 MARKED SNIFF VIOLATIONS AUTOMATICALLY
------------------------------------------------------------------------------------------------------
Time: 87ms; Memory: 6Mb
複製程式碼
主要報錯在於:
60 行: output
函式
和 17 行:
好了,我們執行 git commit
試試:
接著我們把這幾個不規範的地方改了之後,同樣執行本地方法,返回結果:
phpcs --standard=PSR2 --encoding=utf-8 -n -p app/Http/Controllers/ApplyController.php
. 1 / 1 (100%)
Time: 44ms; Memory: 6Mb
複製程式碼
我們再執行 git commit
試試:
完美了!
注:「svn」和「git」的區別在於,svn 是放在伺服器上做「pre-commit」檢測的,而「git」是在本地本專案中的,這也是上文說的,如果你用 git 做版本庫,推薦你用「composer」專案安裝的方式安裝工具。
總結
本文以本地 Mac 系統和伺服器 Linux 系統為安裝端,以 VSCode 和 PHPStorm 兩大主流 IDE 作為使用端,以 svn 和 git 為版本庫為例,較為完整而又系統流程的說一說「phpcs」的使用,希望對大家有所幫助!
最後留個小問題:如果你使用 Docker 和 git,怎麼做這一流程式檢測?