使用PhpStorm支援的的PHPDoc寫註解

註解是一定要寫的,但要怎麼寫才能使開發者工具都看得懂呢?PHPDoc是目前PHP註解的標準,提供了統一的註解寫法,並且獲得PhpStorm的支援,PHPUnit也使用PHPDoc,事實上Laravel的source code也是使用PHPDoc格式來寫註解。

Version


PhpStorm 10.0.1

為什麼要寫註解?


  1. 使用人話解釋
    使用人話描述顯示邏輯商業邏輯資料庫邏輯,避免日後需求改變須維護時,自己或其他人看不懂而無法維護。

  2. 讓 IDE得知型別
    PHP是弱型別語言,可以使用type hint,也可使用duck type,當使用duck type時,只有在run time才能得知型別,IDE無法從design time得知型別,因此無法實現code complete與inspection,必須依賴PHPDoc描述型別,這也是PHP比其他語言都更依賴註解的原因。

如何建立PHPDoc?


  1. 在PhpStorm輸入/**,然後按下↩,PhpStorm會自動依據當時的游標的位置產生適當的PHPDoc blocks。

  2. Code->Generate或按⌘ + N,會產生Generate選單,選擇PHPDoc Blocks

  3. 適當時機按下⌥ + ↩,會出現Generate PHPDoc for ...。如剛建立完class, property或method時。

檔頭註解


使用⌘ + N建立PHP Class時,PhpStorm預設會在檔頭插入檔頭註解1 1PhpStorm預設的檔頭註解並非如此,詳細請參考如何修改PhpStorm的檔頭註解?

1
Post model的repository

第1行使用中文敘述整個檔案(整個class)的功能。2 2不建議使用英文寫註解,因為註解主要是給人看的,易懂是其目的,因為每個人對英文的理解程度不一樣,若因此而造成對註解的誤解,就失去寫註解的意義了。

之後會空一行。

@version

1
@version 0.1.0

目前程式的版本,一開始為0.1.0。建議採用Major.Minor.Patch的版本命名方式,也就是Breaks.Features.Fixes3 3詳細請參考Sematic Versioning

@author

1
@author oomusou oomusou@gmail.com

程式一開始建立的原作者。第1個參數為姓名,第2個參數為email。

@date

1
@date 11/22/15

程式一開始建立的日期

@since

1
@since 0.1.0 11/22/15 oomusou: 新增getLatest3Posts()

程式的改版紀錄。第1個參數為版本號,第2個參數為修改日期,第3個參數為修改者名稱,後見加上:,再加上簡易註解

若有很多版本,就繼續加上多個@since

Class註解


使用⌘ + N建立PHP Class時,PhpStorm自動會在class之前插入class註解。4 4interface與trait註解寫法比照class。

1
Class PostRepository

第1行PhpStorm預設使用Class加上class名稱當註解,由於one class per file原則,所以class的註解就相當於檔案的註解,因此不用再特別敘述。

之後會空一行。

@package

1
@package App\Repositories

描述class所屬的namespace,PhpStorm會自動建立。5 5建議每個class都要依據PSR-4的建議使用namespace,詳細請參考如何使用Namespace?

@method

_my_ide_helper.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace Illuminate\Support;

/**
* @method Fluent first()
* @method Fluent after($column)
* @method Fluent change()
* @method Fluent nullable()
* @method Fluent unsigned()
* @method Fluent unique()
* @method Fluent index()
* @method Fluent primary()
* @method Fluent default($value)
* @method Fluent onUpdate($value)
* @method Fluent onDelete($value)
* @method Fluent references($value)
* @method Fluent on($value)
*/

class Fluent {}

平常不會使用,除非使用__call()__callStatic() 動態產生method,由於這種寫法PhpStorm的auto complete抓不到,因次要使用PHPDoc特別描述。6 6在Laravel最典型就是schema builder的unique()nullable(),在Fluent class內是由__call()動態產生,需另外使用PHPDoc的@method加以描述,PhpStorm才可以抓的到。

@property

app/Company.php
1
2
3
4
5
6
7
8
9
/**
* Company
*
* @property integer $id
* @property string $name
* @property string $pairing_code
* @property integer $nation_region_id
* (略)
*/

平常不會使用,除非使用__get()__set() 動態產生 property,由於這種寫法PhpStorm的auto complete抓不到,因此要使用PHPDoc特別描述。7 7在Laravel最典型的就是model的欄位,是使用__get()__set()動態產生property,需使用IDE Helper產生_ide_helper.php,裡面就是用@property描述,PhpStorm才可以抓的到model的欄位。

Property註解


當建立property時,在property上方輸入/** + ↩,PhpStorm會自動產生property的註解。

@var

1
@var Post 注入的post model

對每個property做註解。

第1個參數為property的型別,由於PHP允許duck type,這會導致PhpStorm的auto complete無法執行,所以一定要要輸入型別。

第2個參數為property的註解,使用中文描述該property的意義。

Method註解


  1. 當使用pubf自行建立method時,在method名稱後面按 ⌥ + ↩,PhpStorm會自動根據參數建立method的PHPDoc blocks。

  2. 當使用⌃ + I實踐interface的method時,只要interface有寫好註解,只要在Add PHPDoc選擇Copy from base class,就可以將interface所寫好的註解複製過來。

1
回傳最新3筆文章

第1行使用中文敘述整個method的功能。8 8interface與trait內的method註解寫法,比照class的method。

之後會空一行。

@param

1
@param string $field 排序欄位

對method的每個參數做註解。

第1個參數為傳入參數的型別。
第2個參數為傳入參數的變數。
第3個參數為傳入參數的敘述。

@return

1
@return Collection 最新3筆文章

對method的回傳值做註解。

第1個參數為回傳值的型別。
第2個參數為回傳值的敘述。

為什麼@param與@return對PhpStorm的Auto Complete與Inspection這麼重要?。

由於PHP允許duck type,因此method的參數可以不寫型別,但這樣使得PhpStorm無法在design time得知該參數的型別,因此auto complete與inspection無法執行,所以建議在PHPDoc block一定要加上@param描述參數型別,@return描述回傳型別。此外,若參數為物件,也建議加上class或interface的type hint,一來PhpStorm的auto complete與inspection可以抓到,二來在unit test時,可以使用service container的dependency injection,詳細請參考如何測試內含相依物件的函式?

@throws

1
@throws InvalidArgumentException 若提供的參數不是array型別

若method有使用exception,可使用@throws描述。

第1個參數為exception的型別。
第2個參數為該exception的敘述。

@todo

1
@todo 此段程式碼尚未重構,建議有時間時加以重構

若method尚有功能未完成,可寫在@todo裡。

@since

若之後該method因bug或需求變更而需要維護,使用@since描述其變更,與擋頭註解的@since寫法一樣。

@deprecated

若該API或public method即將在未來版本停用,可加上@depricated,後面加上註解,PhpStorm對於@depricated有特別的支援。

只要使用該API的method,都會加上刪除線提醒。

Method內註解


當PhpStorm無法得知該變數的型別,而導致auto complete與inspection無法執行時,就必須自行使用@var去描述該變數的型別。

@var

最典型的用法是Laravel的Eloquent傳回一個物件,但我們知道他本質上是某個型別的model,但PhpStorm並不知道,因此我們必須自行使用@var加以描述。

PHPUnit註解


PHPUnit也對PHPDoc做了一些擴充,在此僅對最常用的tag加以介紹。

@test

PHPUnit預設會以test開頭的method視為test method,若你不想遵循這個規則,則在method的註解加上@test也可以。

@group

你可以將test method加以分組,將來PHPUnit只測試該group即可。9 9若使用PhpStorm執行PHPUnit,按⌃ + ⇧ + R可對單一method做測試,詳細請參考如何使用PhpStorm測試與除錯?

1
oomusou@mac:~/MyProject$ php vendor/bin/phpunit --group=PostRepository0

@expectedException

若你要測試的就是該method產生exception,PHPUnit並沒有提供對應的assertion,須在test method的註解的方式加上@expectedException,後面加上預期的exception類別。

Conclusion


  • 建議使用中文寫註解,避免因為每個人對於英文的理解不一樣,而造成誤解。
  • 其他程式語言沒有依照一定的格式寫註解,或許問題沒那麼大,但因為PHP為弱型別語言,為了讓IDE能支援auto complete與inspection,使用標準的PHPDoc格式非常重要。
  • PHPDoc不僅僅只有在PhpStorm可用,其他如Sublime Text,Eclipse與Netbeans也都支援PHPDoc。
2015-11-20