Manual:Development Covenant/zh

From Kiwiphp

Jump to: navigation, search
 

kiwiphp倡导契约开发,因此其中有不少约定,仔细阅读这个开发规范有助于更好的使用kiwiphp。

注:此规范是2006年为一个初级工程师组成的小型团队订立,教条性的语句较多,请读者遇到这类语句自动无视-_-

Contents

数据库设计规范

范式

所有数据表都必须满足第一范式。

大部分表还满足第三范式,小部分表出于性能的因素设置部分缓存字段,不满足第三范式。

表名和字段名

参见命名规范部分。

数据类型

对MySQL只有以下数据类型会被用到:

char

定长字段,比如32位密码,在对性能要求高的定长表使用。

int和bigint

凡数字字段都使用int类型,极少数情况下可以用bigint,但不使用MySQL独有的tinyint, smallint, mediumint。仅作为开关使用的字段,也用int类型,不用enum类型。

text

凡超过一定长度(255字节)的文本字段都使用text类型。

varchar

小于255字节的文本字段使用varchar类型。

decimal

用于在对数据精确性要求较高的程序中存储带小数的数据。

是否允许为空

除了主键ID设置为NOT NULL,其他字段都允许为NULL。

默认值

无需指定默认值,改在PHP框架或者Controller中实现。

索引

创建数据库的时候,除了主键默认就有唯一索引,其他所有都不加。等性能测试和调优的时候统一加。

注释

除了按照下面的命名规范做到见名知意外,每个数据表,以及表中除了特殊字段之外的其他字段,都必须写注释。尤其是int类型用作开关(模拟枚举,enum)的时候,哪个数字代表什么意思必须有完整的注释。

特殊字段

每一个表至少应该有如下三个字段:

id

主键ID。

INT(多数情况下)或者BIGINT类型,多数情况下自增。

created

创建时间。

int类型,存储unix timestamp。

modified

最后修改。

int类型,存储unix timestamp。

树型表的特殊字段

我们还有一种特殊的表,用于存储树型结构的层次化数据。此模型请参考Windows资源管理器的文件夹树,或者MSDN左边框的导航树。

这种表还应该具有如下几个特殊字段:

family_id

家族ID。

INT类型(多数情况下)或者BIGINT类型。

同一个树上的所有节点拥有相同的家族ID,这个ID的值就是根节点的主键ID值。

x

水平方向上的位置。

INT类型。

值越大,越靠右。

y

竖直方向上的位置。

INT类型。

值越大,越靠下。

ACL表的特殊字段

role_id

角色ID。

INT类型。

controller

控制器名称。

VARCHAR类型。

action

(控制器)方法名。

VARCHAR类型。

switch

是否允许操作的开关。

INT类型。

字符集

都使用UTF-8编码。

命名规范

两种命名风格

C Style

一种是C style的underscore_words风格,所有的单词都小写,中间用下划线隔开,这种风格,我们下面简称C Style。

CPP Style

另外一种是C++ Style的camelizedWord风格,不使用下划线,每个单词的首字母大写,第一个单词除外。我们下面简CPP Style。

字符组成

若采用C Style的命名规则,一个名字只能由小写字母和下划线组成。

若采用CPP Style的命名规则,一个名字只能由大小写字母组成。不能出现下划线。

我们的各种命名目前还没有数字出现。

基本原则

见名知意

一个名字应当准确无误的反应它的功用,因此:

必须使用恰当的英文单词或者约定俗成的英文缩写

loopTimes arrayLength memberTotal article httpClient 这些都是符合要求的好名字。

不准使用汉语拼音或者拼音缩写

yonghu(用户) grjl(个人简历) 这样的汉语拼音或者拼音缩写不能使用。

长短适中

名字过长会造成输入工作量大,且容易出现拼写错误(在某些没有IDE提示和自动完成的场合),名字太短则容易违反“见名知意”的原则。

一个合适的名字应该在6-16个字符。

不准使用过短且没有意义的名字

如a = 1; b = 2; c = a + b;

只有约定俗成的i,j,k和x,y等例外。

i,j,k一般是循环计数变量,x,y一般是坐标系中的坐标。

不要使用不必要的缩写

如rec(record)、 resu(result)、fh(fileHandle)、rs(recordset)、conn(connection) 这些名字,如果写完整的单词也不会太长,省略这么几个字母,录入量没有减轻多少,可读性却急剧下降。

但,info(information),id(identification),min(minimum),max(maximum)等生活中常用缩略词是允许使用的。

尽量控制在3个单词,16个字符以内

如果名字太长,在不违背上述原则的前提下,考虑用简洁的等价方案。

数据库

采用C Style。

采用CPP Style,第一个单词的第一个字母也大写。就像这样:class Demo

方法

采用CPP Style。

前缀

方法名一般拥有下面这样的前缀:

add

增加。

对应数据库层的insert。

del

删除。

对应数据库层的delete。

get

获取。

对应数据库层的select。

set

修改。

对应数据库层的update。

后缀

Controller里面用于处理表单的方法(即form action指向的方法)和显示该表单的方法名称存在这样的关系:显示该表单的方法名称+Action后缀=用于处理表单的方法名称

比如,修改个人资料的界面是调用这个方法:User::setProfile(),则处理用户提交的资料修改请求的方法名称是:User::setProfileAction()。

特殊方法

构造器

构造器的方法名称都是:__construct()

注意,是两个下划线。

到目前为止,Controller都是没有自定义的构造器的,构造器方法只出现在框架里面。

私有方法

私有方法以下划线开头,如:_getAttachment($mime)

变量

采用CPP Style。

例外:因为字符串索引严格区分大小写,为了避免麻烦,数组变量的字符串索引采用C Style,就像这样:$certainArray['a_good_index_name']

文件

采用C Style。

Windows平台对文件名的大小写不敏感,但是Unix/Linux平台严格区分大小写,因此,所有文件(注意,是所有,不仅仅PHP,资源文件也受此限制)一律使用C Style的命名。

Controller类的文件名就是其类名去掉“Controller”后缀之后的C Style版本,比如UserController控制器的文件名是:user.php

Model类的文件名是其类名的C Style版本,比如EntryTagMapping模型的文件名是:entry_tag_mapping.php View的文件名比较特殊,原则上,它应该是方法名的C Style版本,且存储在以Controller名的子目录下——绝大部分情况下也的确如此,比如,UserController::setProfile()方法对应的View就是:views/user/set_profile.php。

URL

采用C Style。

URL中非用户输入部分(比如查询的关键字)全部小写,URL看起来都是这个样子的:

项目根目录/controller名(C Style)/方法名(C Style)/参数名1/值1/参数名2/值2

例如:magic/passport/user/view/id/3/username/chin

URL 中的参数名若将被传递给Model层,则应该和数据库中对应的字段名保持一致。

表单

采用C Style。

表单元素名若将被传递给Model层,则应该和数据库中对应的字段名保持一致。

编码规范

文件格式

文件开头

除了View,其他php文件必须以

哪怕是个空文件。 不准使用

文件结尾

除了View,其他PHP文件省略PHP闭合标签

除了View文件,其他PHP文件不存在任何输出,整个文件都是一段PHP代码,只有一个标签,这种情况下省略这唯一一个在文件末尾的PHP闭合标签“?>”,不会影响PHP的正常执行。 闭合标签“?>”之后的空白不易被察觉,容易导致包含它的文件往浏览器发送header时出错。

举例说明:

设有一个config.php,存储数据库连接信息:

<?php
//config.php
$config['db']['host'] = 'localhost';
?>     
    

这里才是文件结尾,从“?>”到这里有若干个空格和一个空行,这在编辑器里面是不容易被察觉的。用鼠标拖选就能看到效果了。

有一个admin.php是后台管理界面,需要包含config.php以取得数据库连接信息:

<?php
//admin.php
include('config.php');
if ('administrator' != $_SESSION['role'])
{
	header('Location: login.php');
}
?>
在这里例子里面,config.php文件末尾多余的空格会被当作Content被发送给客户端,当admin.php再发送Header的时候就会出错:在发送Header之前发送了Content。
文件末尾空行

根据Unix环境下的习惯和规范,每个文件的末尾都有一个空行。

换行

用unix标准的LF换行

标准的Unix换行符是LineFeed,它的十六进制代码是0x0A。

行尾不要有多于的空格

有的编辑器会自动去除行尾的空格,因此我们不在行尾加空格。

代码格式

目标:不依赖特定的编辑器,无论在Linux还是Windows下打开,无论是记事本还是Eclipse,都应该看到统一的,一样的格式。

换行

每个语句在单独的一行

除了for循环的圆括号里面可以有三个语句

 for($i = 0; $i < $loopTimes; $i ++)
一个语句应该控制在一行之内

下列情况特别注意:

语句包含比较复杂的数组定义

 $config = array(
 'db' => array(
 'host' => 'devserver',
 'dbname' => 'base'
 )
 );
 

不要用array()构造数组,改为给数组变量赋值:

 $config['db']['host'] = 'devserver';
 $config['db']['dbname'] = 'base';

空行

只有Controller中属性(function之外定义的变量)或方法(function)之间可以空一行。其他地方不能空行。

缩进

缩进单位

使用一个tab作为缩进单位,而不是四个空格。

如果需要输出tab,用\t而不是一个tab。

缩进场合

花括号中的代码块

class DemoClass
{
	public function demoMethod()
	{
		if ($condition)
		{
			for (;;)
			{
				doSomething();
			}
		}
	}
}

switch case中的代码块

switch ($condition)
{
	case 1:
		doSomething();
		break;
	case 2:
		doSomething();
		break;
}

数组元素分行

$statusMessage = array(
	200 => 'OK.',
	401 => 'Unauthorized.',
	403 => 'Forbidden.',
	404 => 'Not found.',
	406 => 'Not acceptable.',
	417 => 'Expectation failed.',
	500 => 'Internal server error.'
);

空格

操作符的前后空一格
 $key = $value;
 $this->template = 'xmlhttp' == $this->userAgent ? null : 'form';
 $i ++;
if, switch, for, foreach, while等控制结构的左括号(即'(')前空一格
 if (isset($status))
 switch ($condition)
 foreach ($vars as $key => $value)
 while ($score_segment < 101)
参数列表的逗号后面空一格
 $uriArray = explode('/', $uriString);

花括号

花括号用于界定代码块。

即便代码块只有一个语句甚至为空,也不可省略花括号

代码块只有一个语句的时候,省略花括号是被编译器允许的,但是日后给这个代码块增加一行的时候,很可能会忘记加上花括号。因此,无论代码块有多少行,都不能省去花括号。

if ($condition)
{
	echo "there is only one statement";
}
for (;;)
{
	//do nothing
}
一个花括号单独占一行

尤其是起始花括号,不用Pear和C风格的。 C和Pear是这样的:

if ($condition) {
	for (;;) {
		doSomething();
	}
}
配对的花括号在同一列上

如果缩进是正确的,则代码必然满足这个要求。 花括号之前有且仅有n个tab,之后没有空格(或者tab),之前的n个tab是缩进产生的。

综合实例
class DemoClass
{
	public function demoMethod()
	{
		if ($condition)
		{
			for (;;)
			{
				doSomething();
			}
		}
	}
}

注释

综合权衡写注释的时间成本和收益,规定只在两种地方写注释:

被其他人调用的类和方法

注释格式:PHPDoc

/**
 * Database Table abstract
 */
abstract class DbTable
{
	/**
	 * The primary key field name
	 *
	 * @var string
	 */
	protected $_primaryKey;

	/**
	 * A shortcut to SELECT COUNT(*) FROM table WHERE condition
	 *
	 * @param array $args
	 * @return integer
	 */
	public function count($args = null)
	{
		return $row['total'];
	}
}
算法或者业务逻辑非常复杂的代码段

注释格式:comment

 /**
 * get application root directory, who contains controllers, models, views
 * then load the application configuration
 * Note: SCRIPT_FILENAME = /path/to/index.php, not /path/to/kiwi.php
 */
 $appDir = dirname($_SERVER['SCRIPT_FILENAME']) . '/app/';