规范
PHP程序编码规范标准
最后修改日期: 2000-11-16
PHP编程标准是经由Todd Hoff许可,基于《C++ 编程标准》为PHP而重写的,
作者为Fredrik Kristiansen,
使用本标准,如果您想拷贝一份留做自用的话,那是完全免费的,这也是我们制作它的原因。假如您发现了任何的错误又或者是有任何的改进,请您给笔者发一个email,以便笔者将它们合并到最新更新中去。
目录
介绍
标准化的重要性
解释
认同观点
项目的四个阶段
命名规则
合适的命名
缩写词不要全部使用大写字母
类命名
类库命名
方法命名
类属性命名
方法中参数命名
变量命名
引用变量和函数返回引用
全局变量
定义命名 / 全局常量
静态变量
函数命名
php文件扩展名
文档规则
评价注释
Comments Should Tell a Story
Document Decisions
使用标头说明
Make Gotchas Explicit
Interface and Implementation Documentation
目录文档
复杂性管理规则
Layering
Open/Closed Principle
Design by Contract
类规则
Different Accessor Styles
别在对象架构期做实际的工作
Thin vs. Fat Class Interfaces
短方法
进程规则
Use a Design Notation and Process
Using Use Cases
Code Reviews
Create a Source Code Control System Early and Not Often
Create a Bug Tracking System Early and Not Often
RCS关键词、更改记录和历史记录规则
Honor Responsibilities
格式化
大括号 {} 规则
缩进/制表符/空格 规则
小括号、关键词和函数 规则
If Then Else 格式
switch 格式
continue,break 和 ? 的使用
每行一个语句
声明块的定位
流行神话
Promise of OO
杂项
不要不可思议的数字
错误返回检测规则
不要采用缺省值测试非零值
布尔逻辑类型
通常避免嵌入式的赋值
重用您和其他人的艰苦工作
使用if (0)来注释外部代码块
其他杂项
--------------------------------------------------------------------------------
介绍
标准化的重要性
标准化问题在某些方面上让每个人头痛,让人人都觉得大家处于同样的境地。这有助于让这些建
议在许多的项目中不断演进,许多公司花费了许多星期逐子字逐句的进行争论。标准化不是特殊
的个人风格,它对本地改良是完全开放的。
优点
当一个项目尝试着遵守公用的标准时,会有以下好处:
程序员可以了解任何代码,弄清程序的状况
新人可以很快的适应环境
防止新接触php的人出于节省时间的需要,自创一套风格并养成终生的习惯
防止新接触php的人一次次的犯同样的错误
在一致的环境下,人们可以减少犯错的机会
程序员们有了一致的敌人 :-)
缺点
现在轮到坏处了:
因为标准由一些不懂得php的人所制定,所以标准通常看上去很傻
因为标准跟我做的不一样,所以标准通常看上去很傻
标准降低了创造力
标准在长期互相合作的人群中是没有必要的
标准强迫太多的格式
总之人们忽视标准
讨论
许多项目的经验能得出这样的结论:采用编程标准可以使项目更加顺利地完成。标准是成功的关
键么?当然不。但它们可以帮助我们,而且我们需要我们能得到的所有的帮助!老实说,对一个
细节标准的大部分争论主要是源自自负思想。对一个合理的标准的很少决定能被说为是缺乏技术
性的话,那只是口味的原因罢了。所以,要灵活的控制自负思想,记住,任何项目都取决于团队
合作的努力。
解释
惯例
在本文档中使用“要”字所指的是使用本规范的所有项目需要遵守规定的标准。
使用“应该”一词的作用是指导项目定制项目细节规范。因为项目必须适当的包括 (include),
排除(exclude)或定制(tailor)需求。
使用“可以”一词的作用与“应该”类似,因为它指明了可选的需求。
标准实施
首先应该在开发小组的内部找出所有的最重要的元素,也许标准对你的状况还不够恰当。它可能已经概
括了 重要的问题,也可能还有人对其中的某些问题表示强烈的反对。
无论在什么情况下,只要最后顺利的话,人们将成熟的明白到这个标准是合理的,然后其他的程序员们
也会发现它的合理性,并觉得带着一些保留去遵循这一标准是值得的。
如果没有自愿的合作,可以制定需求:标准一定要经过代码的检验。
如果没有检验的话,这个解决方案仅仅是一个建立在不精确的基础上的一大群可笑的人。
认同观点
这行不通;
也许可行吧,但是它既不实用又无聊;
这是真的,而且我也告诉过你啊;
这个是我先想到的;
本来就应该这样。
如果您带着否定的成见而来看待事物的话,请您保持开放的思想。你仍可以做出它是废话的结论,但是做
出结论的方法就是你必须要能够接受不同的思想。请您给自己一点时间去做到它。
项目的四个阶段
数据库结构
设计
数据层
HTML层
--------------------------------------------------------------------------------
命名规则
合适的命名
命名是程序规划的核心。古人相信只要知道一个人真正的名字就会获得凌驾于那个人之上的不可思议的力
量。只要你给事物想到正确的名字,就会给你以及后来的人带来比代码更强的力量。别笑!
名字就是事物在它所处的生态环境中一个长久而深远的结果。总的来说,只有了解系统的程序员才能为系
统取出最合适的名字。如果所有的命名都与其自然相适合,则关系清晰,含义可以推导得出,一般人的推
想也能在意料之中。
如果你发觉你的命名只有少量能和其对应事物相匹配的话, 最好还是重新好好再看看你的设计吧。
类命名
在为类(class )命名前首先要知道它是什么。如果通过类名的提供的线索,你还是想不起这个类是
什么 的话,那么你的设计就还做的不够好。
超过三个词组成的混合名是容易造成系统各个实体间的混淆,再看看你的设计,尝试使用(CRC Se-
ssion card)看看该命名所对应的实体是否有着那么多的功用。
对于派生类的命名应该避免带其父类名的诱惑,一个类的名字只与它自身有关,和它的父类叫什么无
关。
有时后缀名是有用的,例如:如果你的系统使用了代理(agent ),那么就把某个部件命名为“下
载代理”(DownloadAgent)用以真正的传送信息。
方法和函数命名
通常每个方法和函数都是执行一个动作的,所以对它们的命名应该清楚的说明它们是做什么的:用
CheckForErrors()代替ErrorCheck(),用DumpDataToFile()代替DataFile()。这么做也可以使功能和
数据成为更可区分的物体。
有时后缀名是有用的:
Max - 含义为某实体所能赋予的最大值。
Cnt - 一个运行中的计数变量的当前值。
Key - 键值。
例如:RetryMax 表示最多重试次数,RetryCnt 表示当前重试次数。
有时前缀名是有用的:
Is - 含义为问一个关于某样事物的问题。无论何时,当人们看到Is就会知道这是一个问题。
Get - 含义为取得一个数值。
Set - 含义为设定一个数值
例如:IsHitRetryLimit。
缩写词不要全部使用大写字母
无论如何,当遇到以下情况,你可以用首字母大写其余字母小写来代替全部使用大写字母的方法来表
示缩写词。
使用: GetHtmlStatistic.
不使用: GetHTMLStatistic.
理由
当命名含有缩略词时,人们似乎有着非常不同的直觉。统一规定是最好,这样一来,命名的含义就完
全可以预知了。
举个NetworkABCKey的例子,注意C是应该是ABC里面的C还是key里面的C,这个是很令人费解的。有些
人不在意这些,其他人却很讨厌这样。所以你会在不同的代码里看到不同的规则,使得你不知道怎么
去叫它。
例如
class FluidOz // 不要写成 FluidOZ
class GetHtmlStatistic // 不要写成 GetHTMLStatistic
--------------------------------------------------------------------------------
类命名
使用大写字母作为词的分隔,其他的字母均使用小写
名字的首字母使用大写
不要使用下划线('_')
理由
根据很多的命名方式,大部分人认为这样是最好的方式。
例如
class NameOneTwo
class Name
--------------------------------------------------------------------------------
类库命名
目前命名空间正在越来越广泛的被采用,以避免不同厂商和团体类库间的类名冲突。
当尚未采用命名空间的时候,为了避免类名冲突,一般的做法是在类名前加上独特的前缀,两个字符就
可以了,当然多用一些会更好。
例如
John Johnson的数据结构类库可以用Jj做为前缀,如下:
class JjLinkList
{
}
--------------------------------------------------------------------------------
方法命名
采用与类命名一致的规则
理由
使用所有不同规则的大部分人发现这是最好的折衷办法。
例如
class NameOneTwo
{
function DoIt() {};
function HandleError() {};
}
--------------------------------------------------------------------------------
类属性命名
属性命名应该以字符‘m’为前缀。
前缀‘m’后采用于类命名一致的规则。
‘m’总是在名字的开头起修饰作用,就像以‘r’开头表示引用一样。
理由
前缀'm'防止类属性和方法名发生任何冲突。你的方法名和属性名经常会很类似,特别是存取元素。
例如
class NameOneTwo
{
function VarAbc() {};
function ErrorNumber() {};
var mVarAbc;
var mErrorNumber;
var mrName;
}
--------------------------------------------------------------------------------
方法中参数命名
第一个字符使用小写字母。
在首字符后的所有字都按照类命名规则首字符大写。
理由
你可以随时知道那个变量对应那个变量。
你可以使用与类名相似的名称而不至于产生重名冲突。
例如
class NameOneTwo
{
function StartYourEngines(
&$rSomeEngine,
&$rAnotherEngine);
}
--------------------------------------------------------------------------------
变量命名
所有字母都使用小写
使用'_'作为每个词的分界。
理由
通过这一途径,代码中变量的作用域是清晰的。
所有的变量在代码中都看起来不同,容易辨认。
例如
function HandleError($errorNumber)
{
$error = OsErr();
$time_of_error = OsErr->getTimeOfError;
$error_processor = OsErr->getErrorProcessor;
}
--------------------------------------------------------------------------------
引用变量和函数返回引用
引用必须带‘r’前缀
理由
使得类型不同的变量容易辨认
它可以确定哪个方法返回可更改对象,哪个方法返回不可更改对象。
例如
class Test
{
var mrStatus;
function DoSomething(&$rStatus) {};
function &rStatus() {};
}
--------------------------------------------------------------------------------
全局变量
全局变量应该带前缀‘g’。
理由
知道一个变量的作用域是非常重要的。
例如
global $gLog;
global &$grLog;
--------------------------------------------------------------------------------
定义命名 / 全局常量
全局常量用'_'分隔每个单词。
理由
这是命名全局常量的传统。你要注意不要与其它的定义相冲突。
例如
define("A_GLOBAL_CONSTANT", "Hello world!");
--------------------------------------------------------------------------------
静态变量
静态变量应该带前缀‘s’。
理由
知道一个变量的作用域是非常重要的。
例如
function test(){ static $msStatus = 0;
}
--------------------------------------------------------------------------------
函数命名
函数名字采用C GNU的惯例,所有的字母使用小写字母,使用'_'分割单词。
理由
这样可以更易于区分相关联的类名。
例如
function some_bloody_function()
{
}
--------------------------------------------------------------------------------
错误返回检测规则
检查所有的系统调用的错误信息,除非你要忽略错误。
为每条系统错误消息定义好系统错误文本以便include。
--------------------------------------------------------------------------------
大括号 {} 规则
在三种主要的大括号放置规则中,有两种是可以接受的,如下的第一种是最好的:
将大括号放置在关键词下方的同列处:
if ($condition) while ($condition)
{ {
... ...
} }
传统的UNIX的括号规则是,首括号与关键词同行,尾括号与关键字同列:
if ($condition) { while ($condition) {
... ...
} }
理由
引起剧烈争论的非原则的问题可通过折衷的办法解决,两种方法任意一种都是可以接受的,然而对于大
多数人来说更喜欢第一种。原因就是心理研究学习范畴的东西了。
对于更喜欢第一种还有着更多的原因。如果您使用的字符编辑器支持括号匹配功能的话(例如vi),最
重要的就是有一个好的样式。为什么?我们说当你有一大块的程序而且想知道这一大块程序是在哪儿结
束的话。你先移到开始的括号,按下按钮编辑器就会找到与之对应的结束括号,例如:
if ($very_long_condition && $second_very_long_condition)
{
...
}
else if (...)
{
...
}
从一个程序块移动到另一个程序块只需要用光标和你的括号匹配键就可以了,不需要来回的移动到行末去
找匹配的括号。
--------------------------------------------------------------------------------
缩进/制表符/空格 规则
使用制表符缩进。
使用三到四个空格为每层次缩进。
不再使用只要一有需要就缩排的方法。对与最大缩进层数,并没有一个固定的规矩,假如缩进层数大于四或
者五层的时候,你可以考虑着将代码因数分解(factoring out code)。
理由
许多编程者支持制表符。
Tabs was invented for a rason
当人们使用差异太大的制表符标准的话,会使阅读代码变得很费力。
如此多的人愿意限定最大的缩进层数,它通常从未被看作是一件工作。我们相信程序员们会明智的选择嵌套
的深度。
例如
function func()
{
if (something bad)
{
if (another thing bad)
{
while (more input)
{
}
}
}
}
--------------------------------------------------------------------------------
小括号、关键词和函数 规则
不要把小括号和关键词紧贴在一起,要用空格隔开它们。
不要把小括号和函数名紧贴在一起。
除非必要,不要在Return返回语句中使用小括号。
理由
关键字不是函数。如果小括号紧贴着函数名和关键字,二者很容易被看成是一体的。
例如
if (condition)
{
}
while (condition)
{
}
strcmp($s, $s1);
return 1;
--------------------------------------------------------------------------------
RCS关键词、更改记录和历史记录规则
直接使用RCS关键词的规则必须改变,其中包括使用CVS等类似的支持RCS风格关键词的源代码控制系统:
别在文件以内使用 RCS 关键词。
别在文件中保存历史修改记录。
别在文件中保存作者信息记录。
理由
The reasoning is your source control system already keeps all this information. There is no reason to clutter up source files with duplicate information that:
makes the files larger
makes doing diffs difficult as non source code lines change
makes the entry into the file dozens of lines lower in the file which makes a search or jump necessary for each file
is easily available from the source code control system and does not need embedding in the file
When files must be sent to other organizations the comments may contain internal details that should not be exposed to outsiders.
--------------------------------------------------------------------------------
别在对象架构期做实际的工作
别在对象架构期做真实的工作,在架构期初始化变量和/或做任何不会有失误的事情。
当完成对象架构时,为该对象建立一个Open()方法,Open()方法应该以对象实体命名。
理由
构造不能返回错误 。
例如
class Device
{
function Device() { /* initialize and other stuff */ }
function Open() { return FAIL; }
};
$dev = new Device;
if (FAIL == $dev->Open()) exit(1);
--------------------------------------------------------------------------------