内部用Drupal/PHP开发规范1.2
前言
常言道,“没有规矩,不成方圆”。良好的编程风格与规范对开发者以及项目管理人员都是非常重要的。
当一个软件项目尝试着遵守公共一致的标准时,可以使参与项目的开发人员更容易了解项目中的代码、弄清程序的状况。使新的参与者可以很快的适应环境,防止部分参与者出于节省时间的需要,自创一套风格并养成终生的习惯,导致其它人在阅读时浪费过多的时间和精力。而且在一致的环境下,也可以减少编码出错的机会。缺陷是由于每个人的标准不同,所以需要一段时间来适应和改变自己的编码风格,暂时性的降底了工作效率。从使项目长远健康的发展以及后期更高的团队工作效率来考虑暂时的工作效率降低是值得的,也是必须要经过的一个过程。标准不是项目成功的关键,但可以帮助我们在团队协作中有更高的效率并且更加顺利的完成既定的任务。
第1章、排版规则
1.1、缩进
代码缩进使用2个空格,而不是tab键,因为在不同的编辑器查看代码时,tab键的显示出来的长度根是不一样的,虽然空格会增加文件的大小,这些误差是微不足道的。
在很多编辑器中,都可以设置将tab键设置为2个空格,如果你习惯使用tab键的话。
1.2、空格规则
空格应该在以下情况下使用:
1. 关键字与(之间应该有1个空格,例:
<?php
while ($user->uid > 0) {
?>
2. 函数名和(之间不应该有空格,例:
<?php
function arg() {
?>
3. 一元操作符与其操作数之间不应该有空格,除非操作数是个单词,例:typeof。
4. 每个在控制部分,例for语句中,“;”后必须跟一个空格。
5. 每个,后应跟一个空格。
1.2.1、逻辑运算符前后都必须加空格,加一减一运算除外
<?php
// 正确
$a == $b;
// 错误
$a==$b;
$a ==$b;
// 正确
$a++;
$a--;
// 错误
$a ++;
$a --;
?>
1.2.2、多个参数分隔时必须加空格
<?php
// 正确
$a, $ab, $c;
arg($a, $b, $c);
// 错误
$a,$ab,$c;
arg($a,$b,$c);
?>
1.2.3、语法关键字后必须加空格
if, for, while, switch等关键字。
例:
<?php
// 正确
for ($a = 0;$ // 错误
for($a = 0;$ ?>
1.3、字符串和变量的连接规则
字符串与变量连接使用“.”,且在“.”左右都有1个空格,使用"自动转义变量时必须在变量前后加“{}”
<?php
// 正确
$result = 'file_' . $var;
$result = 'file_{var}';
// 错误
$result = 'file_'.$var;
$result = 'file_$var';
?>
1.4、每行一个语句,除非这些语句有很密切的联系,否则每行只写一个语句。用空行来将逻辑相关的语句分隔开以提高程序的可读性。
正确
<?php
$node_types = node_get_types('types', NULL, TRUE);
foreach ($node_types as $type => $info) {
//
}
?>
错误
<?php
$node_types = node_get_types('types', NULL, TRUE);
foreach ($node_types as $type => $info) {
//
}
?>
1.5、关键字
if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要有完整的括号{}
例:
正确
<?php
if (NULL == $arg) {
return;
}
?>
错误
<?php
if (NULL == $arg) return;
?>
1.5.1、if
格式如下:
<?php
if (condition) {
//
}
if (condition) {
//
} else {
}
if (condition) {
//
} else {
//
}
?>
1.5.2、for
格式如下:
<?php
for ($i = 0; $i //
}
?>
1.5.3、do
格式如下:
不像其他复合语句,do语句总是以“;”结束。
<?php
do {
//
} while (condition);
?>
1.5.4、do
格式如下:
<?php
switch (expression) {
case expression:
statements;
default:
statements;
}
?>
每一组statements(除了default,应以break、return或者throw结尾。不要让它顺次往下执行。)
1.5.5、try
格式如下:
<?php
try {
statements
} catch (variable) {
statements
}
?>
1.6、数据库
* 查询语句中关键字部分应该大写。
第2章、命名规范
命名统一遵守Linux C命名规范,包括PHP、XHTML、css、JS。
变量名所有字母都小写,使用“_”作为每个词的分界(CSS中使用“-”,因为很多drupal生成的代码都用“-”(例如区块ID,通常为类似#block-vacation)。),变量名必须有一定的意义,使程序一目了然。
在项目中,相同意义的变量变量名应该尽量相同,例:drupal项目中$node表示节点,节点在很多地方都使用到,如果命名相同,一眼就可知道这是个节点,可以使用节点的相关函数操作,如要区分多个节点,则可以加上有意义的字母在前,例:$book_node、$color_node。
2.1、常量
PHP的常量应该全部使用大写字母,并使用_来正确的分隔字词。
常量使用模块名来作为前缀,这样个可以避免常用字词的冲突。例:你的模块名为test.module,那么常量名字应该如例TEST_USER。
<?php
define('TEST_CONFIRM_UID', 0);
?>
2.2、全局变量
全局变量命名规则:$_模块名(主题名)_全局变量名
例:
<?php
// 错误
globe $records;
// 正确
globe $_test_records;
?>
2.3、静态变量
静态变量使用前缀s,例:
<?php
$s_records;
?>
2.4、临时变量
不要将在循环中频繁使用的临时变量如$i、$j等用于其他用途。
2.5、函数命名
函数名采用C GUN的惯例,所有字母使用小写字母,规则:模块名+_+函数名,要注意的是命名时不要与drupal的相关hook重名。
2.6、文件名命名
文件名应该都是小写的。例外情况就是文档文件,它们全部大写并且类型为txt文件。
例如:
LICENSE.txt
README.txt
INSTALL.txt
第3章、编程规范
系统统一使用时间戳time()作为时间标志,存入mysql时使用INT(10)类型写入。
引号使用单引号,只有当引号重叠时才使用双引号,这样每进程可以省几百K内存。
统一使用
<?php
?>,禁止使用
?>
3.1、数组定义规则
key、值必须使用单/双引号。
<?php
// 正确
array(
'name' => 'myname',
'type' => 'mytype'
);
// 错误
array(
name => myname,
type => mytype
);
?>
3.2、不采用缺省方式测试变量/函数
<?php
// 正确
if ($user > 0) {
//
}
if (arg(1) != '') {
//
}
// 错误
if ($user) {
//
}
if (arg(1)) {
//
}
?>
3.3、文件结构规则
drupal模块开发规则如下(以模块名为book为例):
主模块(book.module)包含 hook_help()、hook_init()、hook_menu()以及该模块的一些共用函数,如需要调用其他模块的函数(必须启用的核心模块除外),应先判断该模块是否开启(例:module_exists('book');)。
book.admin.inc(管理页面相关代码)、book.page.inc(用户操作所用代码),应该归类放置,使用hook_menu中“file”键指向。
模块中使用到的一些js插件,如jquery插件,应放在模块目录中js文件夹中。
3.4、数据库操作规则
* 查询1条以及多条记录时,使用db_query_range()。
* 每次查询如果可以都应该加上ORDER针对INDEX排序。
3.5、注释
注释文档遵循Doxygen注释样式,注释块语法如下(包括css、js):
<?php
/**
* Implementation of hook_cron().
*/
function node_cron() {
db_query('DELETE FROM {history} WHERE timestamp }
?>
注释块必须紧挨着放在函数前,中间不存在空行。
drupal能够理解下面所列的Doxygen构造体,具体构造体作用请参照Doxygen文档:
* @mainpage
* @file
* @defgroup
* @ingroup
* @addtogroup
* @param
* @return
* @link
* @see
* @{
* @}
3.5.1、// $id$
“// $id$”用于追踪版本号以及最后修改的用户,以注释方式放在每个文件最前头(包括js、css等所有需要提交到版本库的文件)。当把代码提交到CVS(SVN),系统将会自动对这一标签进行解析和扩展,变成如下:
<?php
// $Id: node.module,v 1.947.2.29 2010/12/15 12:53:33 goba Exp $
?>
第4章、编写安全的代码
4.1、处理用户输入输出
非drupal hook_form生成的表单(包括一些ajax)提交上的数据,应该进行安全过滤。以下列出drupal提供的一些过滤函数。
* check_plain(HTML),转换为纯文本,将特定字符转换为HTML实体。
* filter_xss(HTML),使用一组标签,检查和清理HTML
* check_markup(HTML),使用过滤器(可以自定义)过滤
* drupal_urlencode(URL),将特定字符编码为%0x
* check_url(URL),清理url中有害协议,例如javascript:runevilJS()
通常在输出中,应该用t()函数,来过滤输出,以便支持drupal的多语言模块。
4.2、处理mysql语句
进行数据库的增删查改操作时,都要使用db_query()函数(drupal7使用方法有变动,具体请参照相关资料),表名必须使用大括号,这样在有数据库前缀的时候,可以自动判断。如下:
<?php
/**
* Implementation of hook_cron().
*/
function node_cron() {
db_query('DELETE FROM {history} WHERE timestamp }
?>
4.2.1、使用db_rewrite_sql()来保持私有数据的私有性
如果启用了节点访问模块对节点访问进行了权限控制,那么直接通过db_query()查出的数据是无法进行权限过滤的,这时候,需要用到db_rewrite_sql(),在一些节点数据的操作上,如果mysql语句没处理到权限部分,则必须使用该函数。例:
<?php
$result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (". db_placeholders($rids) .") OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), array_merge(array($theme_key), $rids));
?>
第5章、其他重要杂项
* 不到万不得已,不修改drupal核心代码,如有修改,应在开发文档中有记录。
* 模块中HTML展示部分尽量都使用默认风格,例、table(theme('table', $header, $rows))、list(theme('item_list', $items))等,如特殊风格部分,HTML、CSS都应该写在模块中,而不是依赖主题,这样,在主题的切换中,就不会导致无法使用。
* 所有的链接都必须使用l()函数,该函数会自动判断网站根目录位置,避免在网站迁移后有死链接。
* 访问权限控制尽量捆绑在hook_menu上,不应该在函数内有过多的判断。