PHP编程规范

PHP编程规范

本规范参考自PHP-FIG(框架协同工作组)的PSR-0PSR-1PSR-2中文翻译组

参考 Symfony Standards

RFC 2119中的必须(MUST)不可(MUST NOT)建议(SHOULD)不建议(SHOULD NOT)可以/可能(MAY)等关键词将在本规范中用来做一些解释性的描述。

1. 通则


1.1. 术语

  • 术语“类”指所有的类(class)接口(interface)特性(trait)

1.2. 源文件

  • 源文件的编码格式必须只使用不带字节顺序标记(BOM)UTF-8
  • 源文件必须使用Unix LF(换行)作为行结束符。
  • 源文件必须只使用 <?php<?= 这两种标签,不可使用短标签,关闭标签?> 必须省略。
  • 源文件必须以一个空行结束。
  • 一个源文件建议只用来做声明(类(class)函数(function)常量(constant)等)或者只用来做一些引起副作用的操作(例如:输出信息,修改.ini配置等),但不建议同时做这两件事。
  • 一个源文件必须只能包含一个类(class)

1.3. 行

  • 一行代码的长度不建议有硬限制;软限制必须为120个字符,建议每行代码80个字符或者更少;较长的行建议拆分成多个不超过80个字符的子行。
  • 在非空行后面不可有空格。
  • 空行可以用来增强可读性和区分相关代码块。
  • 一行不可多于一个语句。

1.4. 缩进

  • 代码必须使用4个空格,且不可使用制表符来作为缩进。

注意:代码中只使用空格,且不和制表符混合使用,将会对避免代码差异,补丁,历史和注解中的一些问题有帮助。空格的使用还可以使通过调整细微的缩进来改进行间对齐变得更加的简单。

1.5. 关键字和 true/false/null

  • PHP关键字(keywords)必须使用小写字母。
  • PHP常量true, falsenull 必须使用小写字母。

2. 命名空间(Namespace)导入(Use)声明


  • 一个完全标准的命名空间(namespace)类(class)的结构是这样的:\<Vendor Name>\(<Namespace>\)*<Class Name>
  • 每个命名空间(namespace)都必须有一个顶级的空间名(namespace)("组织名(Vendor Name)")。
  • 每个命名空间(namespace)中可以根据需要使用任意数量的子命名空间(sub-namespace)
  • 组织名(vendor name)空间名(namespace)类名(class name)都由大小写字母组合而成。
  • 命名空间(namespace)的声明后面必须有一行空行。
  • 所有的导入(use)声明必须放在命名空间(namespace)声明的下面。
  • 一句声明中,必须只有一个导入(use)关键字。
  • 导入(use)声明代码块后面必须有一行空行。

3. 类


  • 一个源文件中只能有一个类(class),并且每个类(class)至少要有一级空间名(namespace:即一个顶级的组织名(vendor name)
  • 类名(class name) 必须使用大驼峰式(UpperCamelCase)写法。
  • 类(class)中的常量必须只由大写字母和下划线(_)组成。
  • 属性(property)方法名(method name) 必须使用小驼峰式(lowerCamelCase)写法。

3.1. 扩展(extend)实现(implement)

  • 一个类的扩展(extend)实现(implement)关键词必须类名(class name)在同一行。
  • 类(class)的左花括号必须放在下面自成一行;右花括号必须放在类(class)主体的后面自成一行。
<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // 常量、属性、方法
}
  • 实现(implement)列表可以被拆分为多个缩进了一次的子行。如果要拆成多个子行,列表的第一项必须要放在下一行,并且每行必须只有一个接口(interface)
<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // 常量、属性、方法
}

3.2. 属性(property)

  • 所有的属性(property)必须声明其可见性。
  • 变量(var)关键字不可用来声明一个属性(property)
  • 一条语句不可声明多个属性(property)
  • 属性名(property name) 不推荐用单个下划线作为前缀来表明其保护(protected)私有(private)的可见性。

一个属性(property)声明看起来应该像下面这样。

<?php
namespace Vendor\Package;

class ClassName
{
    public $foo = null;
}

3.3. 方法(method)

  • 所有的方法(method)必须声明其可见性。
  • 方法名(method name) 不推荐用单个下划线作为前缀来表明其保护(protected)私有(private)的可见性。
  • 方法名(method name)在其声明后面不可有空格跟随。其左花括号必须放在下面自成一行,且右花括号必须放在方法主体的下面自成一行。左括号后面不可有空格,且右括号前面也不可有空格。
  • 一个方法(method)声明看来应该像下面这样。 注意括号,逗号,空格和花括号的位置:
<?php
namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // 方法主体部分
    }
}

3.4. 方法(method)的参数

  • 在参数列表中,逗号之前不可有空格,而逗号之后则必须要有一个空格。
  • 方法(method)中有默认值的参数必须放在参数列表的最后面。
<?php
namespace Vendor\Package;

class ClassName
{
    public function foo($arg1, &$arg2, $arg3 = [])
    {
        // 方法主体部分
    }
}
  • 参数列表可以被拆分为多个缩进了一次的子行。如果要拆分成多个子行,参数列表的第一项必须放在下一行,并且每行必须只有一个参数。
  • 当参数列表被拆分成多个子行,右括号和左花括号之间必须有一个空格并且自成一行。
<?php
namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // 方法主体部分
    }
}

3.5. 抽象(abstract)终结(final)静态(static)

  • 当用到抽象(abstract)终结(final)来做类声明时,它们必须放在可见性声明的前面。
  • 而当用到静态(static)来做类声明时,则必须放在可见性声明的后面。
<?php
namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // 方法主体部分
    }
}

3.6. 调用方法和函数

  • 调用一个方法或函数时,在方法名或者函数名和左括号之间不可有空格,左括号之后不可有空格,右括号之前也不可有空格。参数列表中,逗号之前不可有空格,逗号之后则必须有一个空格。
<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);
  • 参数列表可以被拆分成多个缩进了一次的子行。如果拆分成子行,列表中的第一项必须放在下一行,并且每一行必须只能有一个参数。
<?php
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

4. 控制结构


下面是对于控制结构代码风格的概括:

  • 控制结构的关键词之后必须有一个空格。
  • 控制结构的左括号之后不可有空格。
  • 控制结构的右括号之前不可有空格。
  • 控制结构的右括号和左花括号之间必须有一个空格。
  • 控制结构的代码主体必须进行一次缩进。
  • 控制结构的右花括号必须主体的下一行。

每个控制结构的代码主体必须被括在花括号里。这样可是使代码看上去更加标准化,并且加入新代码的时候还可以因此而减少引入错误的可能性。

4.1. ifelseifelse

  • 下面是一个if条件控制结构的示例,注意其中括号,空格和花括号的位置。同时注意elseelseif要和前一个条件控制结构的右花括号在同一行。
<?php
if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}
  • 推荐elseif来替代else if,以保持所有的条件控制关键字看起来像是一个单词。

4.2. switchcase

  • 下面是一个switch条件控制结构的示例,注意其中括号,空格和花括号的位置。case语句必须要缩进一级,而break关键字(或其他中止关键字)必须case结构的代码主体在同一个缩进层级。如果一个有主体代码的case结构故意的继续向下执行则必须要有一个类似于// no break的注释。
<?php
switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

4.3. whiledo while

  • 下面是一个while循环控制结构的示例,注意其中括号,空格和花括号的位置。
<?php
while ($expr) {
    // structure body
}
  • 下面是一个do while循环控制结构的示例,注意其中括号,空格和花括号的位置。
<?php
do {
    // structure body;
} while ($expr);

4.4. for

  • 下面是一个for循环控制结构的示例,注意其中括号,空格和花括号的位置。
<?php
for ($i = 0; $i < 10; $i++) {
    // for body
}

4.5. foreach

  • 下面是一个for循环控制结构的示例,注意其中括号,空格和花括号的位置。
<?php
foreach ($iterable as $key => $value) {
    // foreach body
}

4.6. try, catch

  • 下面是一个try catch异常处理控制结构的示例,注意其中括号,空格和花括号的位置。
<?php
try {
    // try body
} catch (FirstExceptionType $e) {
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

5. 闭包


  • 声明闭包时所用的function关键字之后必须要有一个空格,而use关键字的前后都要有一个空格。
  • 闭包的左花括号必须跟其在同一行,而右花括号必须在闭包主体的下一行。
  • 闭包的参数列表和变量列表的左括号后面不可有空格,右括号的前面也不可有空格。
  • 闭包的参数列表和变量列表中逗号前面不可有空格,而逗号后面则必须有空格。
  • 闭包的参数列表中带默认值的参数必须放在参数列表的结尾部分。

下面是一个闭包的示例。注意括号,空格和花括号的位置。

<?php
$closureWithArgs = function ($arg1, $arg2) {
    // body
};

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};
  • 参数列表和变量列表可以被拆分成多个缩进了一级的子行。如果要拆分成多个子行,列表中的第一项必须放在下一行,并且每一行必须只放一个参数或变量。
  • 当列表(不管是参数还是变量)最终被拆分成多个子行,右括号和左花括号之间必须要有一个空格并且自成一行。

下面是一个参数列表和变量列表被拆分成多个子行的示例。

<?php
$longArgs_noVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) {
   // body
};

$noArgs_longVars = function () use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_longVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_shortVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use ($var1) {
   // body
};

$shortArgs_longVars = function ($arg) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};
  • 把闭包作为一个参数在函数或者方法中调用时,依然要遵守上述规则。
<?php
$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);

示例

这个示例中简单展示了上文中提到的一些规则:

<?php
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleFunction($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // 方法主体
    }
}

6.数据库规范


  • 表名用英文单词加下划线连接,(如order_detail)

  • 字段类型要经过思考使用合适的类型和长度

  • 建立必要的索引

  • yii建议基本表使用id,name字段来命名,关联表id用下划线_id的形式(如分类表category里有id,name字段,product表有id,name字段和category_id字段)

推荐阅读:[MYSQL性能优化的最佳20+条经验] [MySQL优化原理]
[MYSQL性能优化的最佳20+条经验]:https://coolshell.cn/articles/1846.html
[MySQL优化原理]:https://www.jianshu.com/p/d7665192aaaf

7.代码注释


PHPDoc 是注释 PHP 代码的非正式标准。它有许多不同的标记可以使用。完整的标记列表和范例可以查看 PHPDoc 指南

如下是撰写类方法时的一种写法:


/**
 * @author A Name <a.name@example.com>
 * @link http://www.phpdoc.org/docs/latest/index.html
 */
class DateTimeHelper
{
    /**
     * @param mixed $anything Anything that we can convert to a \DateTime object
     *
     * @throws \InvalidArgumentException
     *
     * @return \DateTime
     */
    public function dateTimeFromAnything($anything)
    {
        $type = gettype($anything);

        switch ($type) {
            // Some code that tries to return a \DateTime object
        }

        throw new \InvalidArgumentException(
            "Failed Converting param of type '{$type}' to DateTime object"
        );
    }

    /**
     * @param mixed $date Anything that we can convert to a \DateTime object
     *
     * @return void
     */
    public function printISO8601Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('c');
    }

    /**
     * @param mixed $date Anything that we can convert to a \DateTime object
     */
    public function printRFC2822Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('r');
    }
}

  • 这个类的说明使用了 @author 和 @link标记, @author 标记是用來说明代码的作者,在多位开发者的情况下,可以同时列出好几位。其次 @link 标记用来提供网站链接,进一步说明代码和网站之间的关系。

  • 在这个类中,第一个方法的 @param 标记,说明类型、名字和传入方法的参数。此外,@return 和 @throws 标记说明返回类型以及可能抛出的异常。

  • 第二、第三个方法非常类似,和第一个方法一样使用一个 @param 标记。第二、和第三个方法之间关键差別在注释区块使用/排除 @return 标记。@return void 标记明确告诉我们没有返回值,而过去省略 @return void 声明也具有相同效果(沒有返回任何值)。

  • 除增删改查等一目了然的action可不加注释外,所有的类、方法都加注释

  • 方法和类的头部注释使用/**/,代码行内使用单行注释//,注释内容前留一个空格

  • 特殊注释// TODO: 待办事项,配合编辑器可以快速定位包含todo的所有文件,比如phpstorm里使用alt+6(mac:cmd+6)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值