Magic numbers should be turned into constants
神奇數字,它應該被替換爲常量

神奇數字式一個沒有解釋其意義的字面值,而且它出現在代碼裏多次。這樣的值將會顯示沒有任何意圖,它應該被替換爲常量:常量的名字將會使代碼更可讀,在未來更加容易更新。

ç

讓我們來看看一些代碼,並且把它的神奇數字分離出來來試圖理解它的情況。這是一個真實的數字的例子,來源於最近發佈的一個關於120 kLOC的開源應用。

 

 

 

Value Number of occurrences
0.0 1
1.0E-08 1
0.05 1
0.33 1
1.0 10
1.7 4
2.0 1
2.3 1
3.2 1
4.0 1
4.199999 1
4.299999 1
5.0 1
5.2 2
7.3 1
8.0 1
365.25 3
3600.0 1

用眼快速地掃一下顯示:

  • 0.33 看上去像是 1/3, 有點取一個近似值。它可以被取代爲用被除數3的除法。
  • 365.25 看上去像一個一年的時間用天表示。另外一個可疑的地方時整數365和366在應用中使用了多次。
  • 幾個整數被表達爲實數(0, 1, 2, 4, 5, 8, 3600)。
  • 有一個小數點的浮點數看上去像版本號但也可能是其他的東西。我們能識別出PHP版本PHP version (5.0, 5.2), 或其他。

 

把字面值轉變成常量

只使用一次的數字可以安全的被忽略。它們可能是用來做測試的目的或邊緣用例,只有微小得重要性。只有至少2次出現的情況才值得創建一個常量。

另一個方面,使用多次的數字也可能顯示不同代碼之接有關係。當遠程(如git版本控制)代碼改變時,任何的更新突然變得困難起來。所有那些值必須被搜索和查閱。讓我們來看看對於1.7的情況。

1.7 在代碼裏顯示了4次。沒有任何對這個值的意義的說明:最好的猜測是它可能是個版本號。Grep命令顯示它在代碼中出現了19次”1.7″:它真的有必要來使用審計工具來得到那些值。這是寫實際的情況:

backend/external/misc/class.captcha.php#70: $fontsize = $this->height/1.7;
backend/external/misc/class.captcha.php#124: $fontsize = $this->height/1.7;
backend/external/misc/class.captcha.php#186: $fontsize = $this->height/1.7;
backend/external/pear.php.net/HTML/Common.php#97:
function apiVersion()
{
return 1.7;
} // end func apiVersion

有3次計算字體尺寸的出現平率。最後一個是被一個pear類返回的類的版本值。這裏有兩個相互衝突(不一樣)的使用同一個數字的情況,通過常量來代替它們將會很有利。

推薦

  • 查找出字面值,特別是那些用於算術的(像上面的計算字體大小的例子)並使用多次的。最主要的目標是常量化constantization (如果這個是個已存在的詞的話).
  • 神奇數字有可能是實數(很少),整數(很多),字符串(非常多)。按這樣的順序來處理它們來提高代碼的可讀性。
  • 常量也許是類的常量(在類中使用)或接口(在多個接口相關的類)常量,或全局常量(爲了測試目的)。記住,const關鍵字將會使常量更有效率,但是沒有define靈活。
  • 相同的字面值可以被定義爲不同的常量:這是可能的而且很平常。
  • “全都是常量而且沒有字面值”是一個壞主意。特別的,0, 1 和只使用了一次的字面值可以放着它們不管。

最後, 用常量來寫下面的代碼是非常漂亮的:

mkdir('path/to/new/dir', MODE_ALL_READ | MODE_ALL_EXEC)

而不要用:

mkdir('path/to/new/dir', 0770).