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).