[译]PHP编码标准

最近打算系统的阅读PHP7源代码,在看代码之前还是准备先系统复习一遍PHP语言,虽然已经用了几年了,但是并不算精通,所以先翻译一下Github上的php编码标准文档,原文如下:

https://github.com/php/php-src/blob/master/CODING_STANDARDS.md

译文

下面列举了一些标准,想在PHP源码中做修改或新增代码的程序员应该遵守这些标准。因为这个标准在PHP3.0版本才出台,基础的代码并没有完全遵守规则,不过之后的新特性都遵守这个规则。此外还有一些部分已经用新的规则重写了。

编码执行标准

  1. 在代码源文件和使用手册中写下文档。

  2. 指向资源的函数不应该释放他们。

    例如,函数function int mail(char *to, char *from)不应该释放to和/或from。

    特殊情况

    • 专门用来做释放资源功能的函数,比如efree()

    • 给函数多加一个布尔类型的参数,如果参数是true就可以释放其他参数,如果不是就不可用释放。

    • 低级别解析器,轻量级合并token缓存和先前的小内存复制野牛代码。

  3. 和相同模块的其他函数微合并的函数,并且在重要功能上互相依赖,应该在注明文档并且使用static关键字。并且尽可能避免这样用。 

  4. 无论何时尽量用预定义和宏,以至于有特殊意义名字的常量可以很容易的被使用。唯一的例外是0和1,因为他们可以用false和true代替。此外,其他的数字常量用来生命不同含义应该使用#define声明。

  5. 当写处理字符串的函数时, 确保记住PHP存储了每一个字符串字面量的长度,并且不应该使用strlen()函数计算。 使用这种方法写函数时,可以充分利用长度的空间,不仅效率高,而且二进制安全。那些修改字符串的函数也会准确得到他们的新长度,而且也会返回新长度,也不比使用strlen()重新计算。 例如 (e.g. php_addslashes())。

  6. 绝不使用strncat()函数。如果你十分确信你知道自己在做什么,请查一次使用手册,再考虑使用这个函数,尽管这样也要尽量避免使用它。 

  7. 在PHP源码中使用PHP_*宏,并且在zend部分源代码使用ZEND_*宏。尽管PHP_*宏大部分是ZEND_*宏的别名,可以让你更好的理解你正在使用的是什么类型的宏。

  8. 当使用#if语句注释代码时,不用只用0。使用"<git username here>_0". 例如, #if FOO_0,F00代表你的git账户用户名f00。这可以更容易追中被注释的代码,特别是在bundle库。

  9. 必要定义一些不可用的函数。例如,如果一个库缺少一个函数,不要定义这个函数的PHP版本,并且不支持不存在函数的运行时错误。最后的使用者应该使用function_exists()函数测试这个函数的存在性。

  10. 推荐使用emalloc(),efree(),estrdup()等函数,以及和他们对应的标准C库函数。 这些函数实现了一个内部的网络安全机制,可以保证一个请求到最后所有的存储单元都得到释放。当以调试模式运行时也提供了有用的内存分配信息。

    几乎所有情况下,使用emalloc()函数回收内存。

    使用malloc()应该被限制在控制或者释放内存的情况下,或者当相关的内存需要在多个请求之间使用。

用户函数/方法命名协议

  1. 用户级别函数名应该用PHP_FUNCTION()宏包围。他们应该小写,应该用强调边界的词语,尽可能使用比较短的词语。因为缩略词会很大削减函数名的可读性,所以尽量不要用缩略词:

    正确的:

    str_word_count
    array_key_exists

    好的:

    date_interval_create_from_date_string
    // Could be 'date_intvl_create_from_date_str'?
    get_html_translation_table()
    // Could be 'html_get_trans_table'?

    错误的:

    hw_GetObjectByQueryCollObj
    pg_setclientencoding
    jf_n_s_i
  2. 如果他们是父集合函数的一部分,父集合应该包含在用户函数名中,并且应该很明确的与父程序和函数家族有关。 应该是以parent_*的形式:

    foo函数类,比如:

    正确的:

    foo_select_bar
    foo_insert_baz
    foo_delete_baz

    错误的:

    fooselect_bar
    fooinsertbaz
    delete_foo_baz
  3. 被用户函数使用的函数名应该是以_php_作为前缀,并且应该后接下划线强调的界定单词,并且是小写单词来描述函数。如果可以,尽可能用static修饰符。

  4. 变量名必须很有意义。尽可能不要用一个单词的变量,除了没有真实意义或者不重要的变量时。 (比如 for (i=0; i<100; i++) ...)。

  5. 变量名应该是小写的。用下划线区分单词。

  6. 以驼峰命名的方法,尽量用比较短的单词。首单词应该是小写的,并且后面每个单词首字母都大写 :

    正确的:

    connect()
    getData()
    buildSomeWidget()

    错误的:

    get_Data()
    buildsomewidget()
    getI()
  7. 类名应该尽可能短,并且是名词,以帕斯卡命名法命名。类中的每隔单词应该以大写字母开头,不使用下划线。如果没有命名空间可用,类名应该继承父集合的名字(比如扩展名)。无论如何都应该尽量避免缩略词和首字母缩略词,除非他们被非常广泛应用比常见的形式  (比如 HTTP 或者 URL)。鉴于首字母缩略词通常是根据他们的符合被写出来,以一个大写字母开头并且后面跟着小写字母的缩略词。下面的几种首字母缩略词的用法通常不被广泛的使用。

    正确的:

    Curl
    CurlResponse
    HTTPStatusCode
    URL
    BTreeMap // B-tree Map
    Id // Identifier
    ID // Identity Document
    Char // Character
    Intl // Internationalization
    Radar // Radio Detecting and Ranging

    错误的:

    curl
    curl_response
    HttpStatusCode
    Url
    BtreeMap
    ID // Identifier
    CHAR
    INTL
    RADAR // Radio Detecting and Ranging

内部函数命名规则

  1. 外部API类的函数应该是以php_modulename_function()命名,避免符号冲突。他们应该是小写的,以下划线分割。 高风险的API必须被定义在头文件php_modulename.h中。

    PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS);

    未暴露的模块函数应该是静态的并且不定义在php_modulename.h中。

    static int php_session_destroy()
  2. 主模块源文件必须被命名在modulename.c中。

  3. 源码中的头文件必须命名在php_modulename.h中。

语法和缩进

  1. 不要用从c++风格的注释 (比如 // 注释)。尽量用C语言风格的注释。PHP是用C语言写的,并且是用任何标准C编译器编译的。尽管一些一些编译器可以支持C语言中使用C++风格的注释,你必须保证你的代码可以在其他的编译器中也可以顺利编译。唯一的例外是Win32代码,因为Win32是VC++特有的。并且这个编译器可以接收C语言中的C++风格注释。

  2. 使用K&R风格。当然,我们不能也不要强制任何人使用他以前没用过的风格,但是,至少当你想要在PHP源代码或者核心模块中提交你的代码,请使用K&R风格。这在任何地方都应该使用,以缩进和注释风格上升到函数声明语法。也要看缩进风格。 

  3. 不要吝啬使用空格和空行。在变量声明部分和块语句间使用空行,也在一个逻辑语句块之间。在两个函数之间使用一个或者个两个空行。下面的例子:

    if (foo) {
        bar;
    }

    比下面更好:

    if(foo)bar;
  4. 使用制表符缩进。一个制表符代表4个空格。在定义,注释和控制结构正确的对齐保持一致很重要。

  5. 预处理起语句必须从一列开始(比如#if) 。预处理语句指令开头应该以#在第一列开头,后面跟一些空格。

测试

  1. PHP的测试扩展应该用*.phpt形式。参考qa.php.net文档。

文档和折叠钩子

为了确保线上文档和代码在一行,每个用户级别函数应该有自己的用户级别函数原型,在函数之前以一行简单的描述说明函数的功能。看起来像下面这样:

/* {{{ proto int abs(int number)
   Returns the absolute value of the number */
PHP_FUNCTION(abs)
{
    ...
}
/* }}} */

 {{{ 符号是默认的折叠方式,在Emacs和vim中(set fdm=marker命令)。当处理大文件时折叠很有用,因为你可以通过滚动键快速定位文件,并且在查看函数时取消折叠就有效。每个函数的结尾的}}}标志了折叠结束。并且应该在一个独立的行。

对doc/genfuncsummary脚本来说,proto关键字只有一个好处,可以生成完整的函数摘要。 在函数原型前的关键词,在没有函数摘要的代码允许我们添加折叠。

可选参数像下面这样写:

/* {{{ proto object imap_header(int stream_id, int msg_no [, int from_length [, int subject_length [, string default_host]]])
   Returns a header object with the defined parameters */

此外,函数原型应该写在一行,尽管这行很乱。

新的实验性的函数

为了减少和一个新函数集合第一个公开的实现有关的问题,通常建议在函数目录第一个实现应该包括标有EXPERIMENTAL的文件, 并且在第一个实现后面跟的是标准的规范函数。

带有EXPERIMENTAL标志的文件应该包括下面的实现:

  • 任何著作信息(已知bug,模块特征)。

  • 注明持续状态对于Git注释可能不太合适。

一般情况下,新的特征应该提交到PECL(php扩展公共库)或者实验性分支,直到有特殊的原因可以加到核心发行版中。

别名和遗留文档

你可能也有一些不赞成的重复名字,比如somedb_select_result 和 somedb_selectresult。由于文档的原因, 这些只会记录当前的名字,以及列举在文档上的父函数别名。为了方便,有复杂不同名字的用户函数,相同函数的别名(比如highlight_file 和 show_source), 会被分别记录。 原型仍然会被包括,并且描述那个函数有别名。

相反地,兼容性的函数名应该可以作为代码基的一部分很合乎情理。参见PHP文档仓库中的README了解更多的相关信息。

总结

文档翻译的有些生涩,一些专有词汇可能不是很合适,但是对了解PHP源码大有裨益。学习之路道阻且长,忽然想起那句话:路漫漫其修远兮,吾将上下而求索。

2020,我来了,加油!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值