Protoss/规范/代码规范

来自Blueidea
< Protoss‎ | 规范
SnakeZero讨论 | 贡献2010-08-23T09:45:58的版本

(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转至: 导航搜索

写在前面: 本规则基于PEAR的代码书写规范,但是又有些许改进,在不同的地方会指出。
规范的代码是从程序员到高级程序员的必经之路,对企业而言,高质量的代码是可复用和可再生的,而那些看起来吃力的“一次性”代码无疑给企业带来了巨大的隐性成本。企业愿意付更高的报酬聘请那些高级程序员,是可以帮他们减少开发成本,尤其是时间。

缩进规则与行书写规范

所有代码中,均使用4个空格作为缩进标准,不允许使用制表符(tab)。
这样做的好处是:不管什么系统或者编辑器下看,代码都是整齐的。在使用SVN、CVS等工具或者查看diff时,不会对编码和阅读人员带来困难。

如果你使用的是的Emacs编辑器,请设置“indent-tabs-mode”。
如果你使用的是大蛇所钟爱的Vim(GVim)的话,请在_vimrc中作如下设置:
set expandtab
set shiftwidth=4
set softtabstop=4
set tabstop=4

所有的[运算符(包括算术运算符、赋值运算符、位运算符、比较运算符等等)]的左边和右边都需要有一个空格。

基本命名规则

全局变量和函数命名等

  • 变量

如果你需要定义一个全局变量的话,应当以美元符号加下划线“$_”开头,后接包名。例如,PEAR包中一个变量就作:$_PEAR_destructor_object_list。

  • 函数的命名

在PEAR的定义中,我们应当使用“驼峰”写法的代码规则,以包名加下划线为前缀。我们以“XML_RPC_serializeData()”来分析。
在命名中缩写词应当全部大写,如上面的XML和RPC,又如Protoss中的“RBAC”(Role-Based Access Control)。如果是几个单词连着写,那么第一个单词应当首字母小写,后面的单词首字母大写,如上面的serializeData。

  • 类中的方法

在类中,public属性的变量或者参数应该以美元符加小写开头变量名来书写,如“$content”,“$mysqlResult”,“$protoss”。
而私有的方法(private)或变量名应该冠以下划线,如“$_mysqlHandle”,“_processMethod()”,“_sort()”,“_intTree()”。
而protected则和public一样,不能加上下划线。

  • 常量

常量的命名应该为全大写,如:DB_DATASOURCENAME 、 SERVICES_AMAZON_S3_LICENSEKEY

控制结构书写规范

Control Structures,多译作控制结构,可以参考[PHP手册]。
其实说白了就是if, for, while, switch这些啦。

条件简单时

<?php
 
if ((condition1) || (condition2)) {
    action1;
} elseif ((condition3) && (condition4)) {
    action2;
} else {
    defaultaction;
}

注意上面这段代码中,if与“(”之间有个空格,两个条件与符号间有空格。“)”与“{”之间有空格,并且是在同一行
else和elseif的前后大括号“}”和“{”都在同一行。

如果是switch的话,写成这样:

<?php
 
switch (condition) {
case 1:
    action1;
    break;
 
case 2:
    action2;
    break;
 
default:
    defaultaction;
    break;
}

注意case和switch的缩进级别是一致的。

条件复杂时

这种写法可以强调第一个条件,同时也属于中规中矩的写法。

<?php
 
if (($condition1
    || $condition2)
    && $condition3
    && $condition4
) {
    //code here
}

下面这种写法是将多个条件对齐。好处显而易见,这样可以方便的一眼扫完所有条件,而且结构清晰。

<?php
 
if (   $condition1
    || $condition2
    || $condition3
) {
    //code here
}
<?php
 
$is_foo = ($condition1 || $condition2);
$is_bar = ($condition3 && $condtion4);
if ($is_foo && $is_bar) {
    // ....
}

三元运算符

<?php
 
$a = $condition1 && $condition2
    ? $foo : $bar;
 
$b = $condition3 && $condition4
    ? $foo_man_this_is_too_long_what_should_i_do
    : $bar;

函数调用的书写规范

单行调用函数

函数调用时,函数名与“(”之间不能有空格;中间的第个参数与其之前的参数后的“,”之间要有一个空格,但是参数自己后面的“,”之间不能有空格;最后一个参数与“)”之间不能有空格。

<?php
$var = foo($bar, $baz, $quux);

如上面的代码所表述的,“=”的两边都需要有空格,但是如果情况特殊,上下文中都是类似的函数调用操作时,应当以“=”为参照物来对齐,如下:

<?php
$short         = foo($bar);
$long_variable = foo($baz);

为了增加可读性,我们也可以在函数/类的方法调用时,写成这样:

<?php
 
$this->callSomeFunction('param1',     'second',        true);
$this->callSomeFunction('parameter2', 'third',         false);
$this->callSomeFunction('3',          'verrrrrrylong', true);

多行书写格式

当一行书写超过80个字节的时候,请分开成多行来书写,如下:

<?php
 
$this->someObject->subObject->callThisFunctionWithALongName(
    $parameterOne, $parameterTwo,
    $aVeryLongParameterThree
);

因为不是每个人都有很宽的显示器的,一般来说,如果看代码需要横向滚屏的话,会很不爽,因此需要分多行书写。为了方便阅读,一些很长的变量名(所以大蛇不建议你用很长的变量名)最好另起一行,同时几个参数写在同一行也是允许的,但是相对所属的调用函数这一级前面要加4个空格的缩进。
另外,要记得行末的“,”要跟着它前面的参数,且中间不能有空格。
好了,让我们来看一个变态点的:

<?php
 
$this->someObject->subObject->callThisFunctionWithALongName(
    $this->someOtherFunc(
        $this->someEvenOtherFunc(
            'Help me!',
            array(
                'foo'  => 'bar',
                'spam' => 'eggs',
            ),
            23
        ),
        $this->someEvenOtherFunc()
    ),
    $this->wowowowowow(12)
);

并不是说一行满了的情况下才需要换行,很多时候为了增加代码的可读性,我们也用换行来书写,就像上面这段这样。还是老话,注意层级关系。

连贯查询是个不错的东西,但是同样也会造成一条语句很长,所以我们也分行来书写,规则是在每个箭头“->”的位置换行,前面同样的是4个空格。

<?php
 
$condition = array(
    $someModel->primaryKey       => 123,
    'some_other_conditions_here' => 'blabla'
);
$someModel->select()
    ->where($condition)
    ->orderby('created DESC');
    ->execute()
    ->fetch();

上下文对齐标准

一般情况,我们这样对齐:

<?php
 
$short  = foo($bar);
$longer = foo($baz);

当上下文的两行代码的变量名都差不多长时,应当以“=”为参照物来对齐,“=”的两边都需要有空格。
但是如果碰到一变量名短的变态,一个长得变态时,应该不去对齐。

<?php
 
$short = foo($bar);
$thisVariableNameIsVeeeeeeeeeeryLong = foo($baz);

过长的语句要分行

 
<?php
$rows[$otherrow->something]->somemethod->returnArray
    =  $this->xajax->getJavascript(t3lib_extMgm::siteRelPath('nr_xajax'));

定义类的书写规范

类名后的大括号“{”要换行顶格书写。

<?php
class Foo_Bar
{
 
    //... code goes here
 
}

Bi system importent.gifNOTICE

本节以下内容为非PEAR的书写规范,但是却是很多年经验的总结,这些经验一部分来自己我自己,另一部分也是“道上”的优秀习惯。


类的命名使用aaa_bbb这样的方法时,应当以“_”为分割符,后段为前段包内的子项,他们是上下级关系。
更多更详细介绍请参考:Protoss中的类命名规范

定义函数的书写规范

标准函数定义书写规范

函数的定义基于K&R标准。

<?php
function fooFunction($arg1, $arg2 = '')
{
    if (condition) {
        statement;
    }
    return $val;
}

引申:
Brian W.Kernighan(柯尼汉)和Dennis M.Ritchie(里奇)合著了影响深远的名著《The C Programming Language》,常常称它为‘K&R’。 带默认值的参数应当写的参数列表的最后几个。通常都要返回有意义的值。下面来看个长点的例子:

<?php
function connect(&$dsn, $persistent = false)
{
    if (is_array($dsn)) {
        $dsninfo = &$dsn;
    } else {
        $dsninfo = DB::parseDSN($dsn);
    }
 
    if (!$dsninfo || !$dsninfo['phptype']) {
        return $this->raiseError();
    }
 
    return true;
}

多行函数定义书写规范

老规矩,每行最多80个字符。超过的话,就要换行。注意几点:

  • 换行后的参数前要有4个空格
  • “)”应该和关键字“function”对齐
  • “)”和“{”之间要有1个空格
<?php
 
function someFunctionWithAVeryLongName($firstParameter = 'something', $secondParameter = 'booooo',
    $third = null, $fourthParameter = false, $fifthParameter = 123.12,
    $sixthParam = true
) {
    //....
}

数组的书写规范

<?php
 
$some_array = array(
    'foo'  => 'bar',
    'spam' => 'ham',
);

数组中的对齐参照物为“=>”,符号左边至少要保证1个空格,而右边也需要1个空格。

注释的书写规范

对于类的在线文档,应该能够被PHPDoc转换,就象JavaDoc那样。[PHPDoc]也是一个PEAR的应用程序,更详细的介绍你可以去 http://www.phpdoc.de/ 查看。除了类的在线文档,建议你应该使用非文档性质的注释来诠释你的代码,当你看到一段代码时想:哦,我想不需要在文档里去仔细描述它吧。那么你最好给这段代码作一个简单的注释,这样防止你会忘记它们是如何工作的。对于注释的形式,C的 /* */和C++的//都不错,不过,不要使用Perl或者shell的#注释方式。

载入文件的书写规范

无论什么时候,当你需要无条件包含进一个class文件,你必须使用requre_once;当你需要条件包含进一个class文件,你必须使用include_once;这样可以保证你要包含的文件只会包含一次,并且这2个语句共用同一个文件列表,所以你无须担心二者会混淆,一旦require_once 包含了一个文件,include_once不会再重复包含相同的文件,反之亦然。

Bi system importent.gifNOTICE

在Protoss中,不要用“include”或者“require”去包含一个按命名规则命名的类,因为当你使用new来实例化的时候,Protoss会自动载入文件。
Protoss的上下文处理方式保证了它不会二次包含同一个文件。它所包含的文件和类都会在上下文中注册。


文件头部注释书写规范

所有需要包含在PEAR核心发布的PHP代码文件,在文件开始的时候,你必须加入以下的注释声明:

/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: 组织机构名称                                                |
// |          Snake.Zero -- Orochi the Great                              |
// +----------------------------------------------------------------------+
//
// $Id$

对于不在PEAR核心代码库中的文件,建议你也在文件的开始处有这样一个类似的注释块,标明版权,协议,作者等等。同时也在第一行加入VIM的MODELINE,这样在VIM中能够保持PEAR的代码风格。

  • CVS标记:

如上面所展示那样,在每个文件中加入CVS的ID标记,如果你编辑或修改的文件中没有这个标记,那么请加入,或者是替换原文件中相类似的表现形式(如"Last modified"等等)

  • URL样本:

你可以参照RFC 2606,使用"www.example.com"作为所有的URL样本。

  • 常量命名:

常量应该尽量使用大写,为了便于理解,使用下划线分割每个单词。同时,你应该常量所在的包名或者是类名作为前缀。比如,对于Bug类中常量应该以Bug_开始。以上是PEAR的编码规则,详细的编码规则可以参考PEAR中的CODING_STANDDARD文件的说明。为了更好地理解这些编码规则,你也可以参考一下现有PEAR核心模块的代码。

文件的相关规范

  • 所有文件必须是unix文件格式
  • 所有文件编码必须是UTF-8
  • 文件以ASCII码来存储

PHP代码标记

以PEAR的方式来书写时:
任何时候都要使用<?php ?>定义你的php代码,而不要简单地使用<? ?>,这样可以保证PEAR的兼容性,也利于跨平台的移植。

Bi system importent.gifNOTICE

事实证明,以“<?php”开头更加规范,但是之后的?>确实可以省略。那样可以减少许多无法预期的意外输出。
在PHP中,不使用“?>”结尾不会引起错误,哪怕连NOTICE也没有。


全文示例

<?php
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
 
/**
 * Short description for file
 *
 * Long description for file (if any)...
 *
 * PHP version 5
 *
 * LICENSE: This source file is subject to version 3.01 of the PHP license
 * that is available through the world-wide-web at the following URI:
 * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
 * the PHP License and are unable to obtain it through the web, please
 * send a note to license@php.net so we can mail you a copy immediately.
 *
 * @category   CategoryName
 * @package    PackageName
 * @author     Original Author <author@example.com>
 * @author     Another Author <another@example.com>
 * @copyright  1997-2005 The PHP Group
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
 * @version    CVS: <?php
$
?> Id:$
 * @link       http://pear.php.net/package/PackageName
 * @see        NetOther, Net_Sample::Net_Sample()
 * @since      File available since Release 1.2.0
 * @deprecated File deprecated in Release 2.0.0
 */
 
/**
 * This is a "Docblock Comment," also known as a "docblock."  The class'
 * docblock, below, contains a complete description of how to write these.
 */
require_once 'PEAR.php';
 
// {{{ constants
 
/**
 * Methods return this if they succeed
 */
define('NET_SAMPLE_OK', 1);
 
// }}}
// {{{ GLOBALS
 
/**
 * The number of objects created
 * @global int $GLOBALS['_NET_SAMPLE_Count']
 */
$GLOBALS['_NET_SAMPLE_Count'] = 0;
 
// }}}
// {{{ Net_Sample
 
/**
 * An example of how to write code to PEAR's standards
 *
 * Docblock comments start with "/**" at the top.  Notice how the "/"
 * lines up with the normal indenting and the asterisks on subsequent rows
 * are in line with the first asterisk.  The last line of comment text
 * should be immediately followed on the next line by the closing asterisk
 * and slash and then the item you are commenting on should be on the next
 * line below that.  Don't add extra lines.  Please put a blank line
 * between paragraphs as well as between the end of the description and
 * the start of the @tags.  Wrap comments before 80 columns in order to
 * ease readability for a wide variety of users.
 *
 * Docblocks can only be used for programming constructs which allow them
 * (classes, properties, methods, defines, includes, globals).  See the
 * phpDocumentor documentation for more information.
 * http://phpdoc.org/docs/HTMLSmartyConverter/default/phpDocumentor/tutorial_phpDocumentor.howto.pkg.html
 *
 * The Javadoc Style Guide is an excellent resource for figuring out
 * how to say what needs to be said in docblock comments.  Much of what is
 * written here is a summary of what is found there, though there are some
 * cases where what's said here overrides what is said there.
 * http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#styleguide
 *
 * The first line of any docblock is the summary.  Make them one short
 * sentence, without a period at the end.  Summaries for classes, properties
 * and constants should omit the subject and simply state the object,
 * because they are describing things rather than actions or behaviors.
 *
 * Below are the tags commonly used for classes. @category through @version
 * are required.  The remainder should only be used when necessary.
 * Please use them in the order they appear here.  phpDocumentor has
 * several other tags available, feel free to use them.
 *
 * @category   CategoryName
 * @package    PackageName
 * @author     Original Author <author@example.com>
 * @author     Another Author <another@example.com>
 * @copyright  1997-2005 The PHP Group
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
 * @version    Release: @package_version@
 * @link       http://pear.php.net/package/PackageName
 * @see        NetOther, Net_Sample::Net_Sample()
 * @since      Class available since Release 1.2.0
 * @deprecated Class deprecated in Release 2.0.0
 */
class Net_Sample
{
    // {{{ properties
 
    /**
     * The status of foo's universe
     *
     * Potential values are 'good', 'fair', 'poor' and 'unknown'.
     *
     * @var string
     */
    var $foo = 'unknown';
 
    /**
     * The status of life
     *
     * Note that names of private properties or methods must be
     * preceeded by an underscore.
     *
     * @var bool
     * @access private
     */
    var $_good = true;
 
    // }}}
    // {{{ setFoo()
 
    /**
     * Registers the status of foo's universe
     *
     * Summaries for methods should use 3rd person declarative rather
     * than 2nd person imperative, beginning with a verb phrase.
     *
     * Summaries should add description beyond the method's name. The
     * best method names are "self-documenting", meaning they tell you
     * basically what the method does.  If the summary merely repeats
     * the method name in sentence form, it is not providing more
     * information.
     *
     * Summary Examples:
     *   + Sets the label              (preferred)
     *   + Set the label               (avoid)
     *   + This method sets the label  (avoid)
     *
     * Below are the tags commonly used for methods.  A @param tag is
     * required for each parameter the method has.  The @return
     * and @access tags are mandatory.  The @throws tag is required if
     * the method uses exceptions.  @static is required if the method can
     * be called statically.  The remainder should only be used when
     * necessary.  Please use them in the order they appear here.
     * phpDocumentor has several other tags available, feel free to use
     * them.
     *
     * The @param tag contains the data type, then the parameter's
     * name, followed by a description.  By convention, the first noun in
     * the description is the data type of the parameter.  Articles like
     * "a", "an", and  "the" can precede the noun.  The descriptions
     * should start with a phrase.  If further description is necessary,
     * follow with sentences.  Having two spaces between the name and the
     * description aids readability.
     *
     * When writing a phrase, do not capitalize and do not end with a
     * period:
     *   + the string to be tested
     *
     * When writing a phrase followed by a sentence, do not capitalize the
     * phrase, but end it with a period to distinguish it from the start
     * of the next sentence:
     *   + the string to be tested. Must use UTF-8 encoding.
     *
     * Return tags should contain the data type then a description of
     * the data returned.  The data type can be any of PHP's data types
     * (int, float, bool, string, array, object, resource, mixed)
     * and should contain the type primarily returned.  For example, if
     * a method returns an object when things work correctly but false
     * when an error happens, say 'object' rather than 'mixed.'  Use
     * 'void' if nothing is returned.
     *
     * Here's an example of how to format examples:
     * <code>
     * require_once 'Net/Sample.php';
     *
     * $s = new Net_Sample();
     * if (PEAR::isError($s)) {
     *     echo $s->getMessage() . "\n";
     * }
     * </code>
     *
     * Here is an example for non-php example or sample:
     * <samp>
     * pear install net_sample
     * </samp>
     *
     * @param string $arg1 the string to quote
     * @param int    $arg2 an integer of how many problems happened.
     *                     Indent to the description's starting point
     *                     for long ones.
     *
     * @return int the integer of the set mode used. FALSE if foo
     *             foo could not be set.
     * @throws exceptionclass [description]
     *
     * @access public
     * @static
     * @see Net_Sample::$foo, Net_Other::someMethod()
     * @since Method available since Release 1.2.0
     * @deprecated Method deprecated in Release 2.0.0
     */
    function setFoo($arg1, $arg2 = 0)
    {
        /*
         * This is a "Block Comment."  The format is the same as
         * Docblock Comments except there is only one asterisk at the
         * top.  phpDocumentor doesn't parse these.
         */
        if ($arg1 == 'good' || $arg1 == 'fair') {
            $this->foo = $arg1;
            return 1;
        } elseif ($arg1 == 'poor' && $arg2 > 1) {
            $this->foo = 'poor';
            return 2;
        } else {
            return false;
        }
    }
 
    // }}}
}
 
// }}}
 
/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * c-hanging-comment-ender-p: nil
 * End:
 */
 
?>