PHP 规范 - Symfony 代码规范

注:规范主要来源于 Symfony Coding Standards ,示例由本人添加,如有错误地方还请多指正。

Symfony 的编码规范是建立在 PSR-1, PSR-2 and PSR-4 的基础上的。

工具

使用 php-cs-fixer 工具来自动检查编码规范

$ cd your-project/
$ php php-cs-fixer.phar fix -v

结构

每个逗号分隔符之后添加一个空格

$arr = [1, 2, 3];

所有的二元运算符左右都添加一个空格,. 运算符除外

$sum = $a + $b;
$name = $firstName.$lastName;

一元运算符紧跟关联的变量,不需要添加空格

if( !$name )

始终使用全等,除非你需要进行一些类型转换(type juggling)

if($rst === true)

使用 ==!====,和 !== 等判断时,需要将不变的量放在左边,避免意外情况出现

if(10 === $number)

多行数组的最后一项始终添加括号

$arr = [
    [1,2],
    [1,2],
];

代码块中除了 return 语句之外还包含其他代码,那么 return 语句之前保留一个空行

// 添加空行
function sum($a, $b)
{
    $sum = $a + $b;

    return $sum;
}

// 只有 return 语句,无需添加空行
function sum($a, $b)
{
    return $a + $b;
}

虽然 return;return null 在语法上没有什么区别。但是在使用上要根据具体的场景来:如果函数不需要返回值,则使用 return; 如果需要返回值但是返回值为 null,就使用 return null

function foo() : void
{
    return;
}

控制语句不能省略花括号

if($a === 1){
    return true;
}

一个文件中只包括一个类。除非是那些不需要在外部实例化的私有的帮助类。

将类的继承和实现的接口声明都写在同一行。

class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract

属性要在方法之前声明

class Foo
{
    private $bar;

    public function foo()
    {

    }
}

方法默认按照可访问性从高到低排列。除此之外,构造函数 __construct、测试方法 setUp()tearDown() 始终放在最前面,以提高可读性

public foo() {}
protected bar() {}
private barz() {}

无论方法中包括多少个参数,都应当在同一行声明

public function __construct($command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60)
{

}

类的实例化始终使用括号

$foo = new Foo();

异常和错误消息字符串必须使用 sprintf 来进行拼接;

throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));

当错误类型为 E_USER_DEPRECATED 时,需要添加 @

@trigger_error("foo", E_USER_DEPRECATED);

数组访问器之间不要存在空格

$arr[0][1];

引用的类如果不属于全局命名空间,则每个类都需要使用 use

use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\LogicException;

注释文档中 @param@return 如果包括 null 类型,要将 null 放在最后面

/**
 * @param int|null
 * @return string|null
 */

命名约定

使用驼峰法 (camelCase) 命名变量、方法或函数

$acceptableContentTypes
hasSession();

使用蛇形 (snake_case) 命名法来命名配置参数以及 Twig 模板变量

framework.csrf_protection
http_status_code

为所有的类添加命名空间,类名始终使用大写驼峰 (UpperCamelCase)

<?php

namespace App;

class FooBar {

}

抽象类添加 abstract 前缀,除了 PHPUnit 的 TestCase 抽象类。

abstract class Helper 
{

}

接口添加 Interface 后缀

interface ExceptionInterface
{
}

Trait 添加 Trait 后缀

trait FooTrait
{
}

异常添加 Exception 后缀

class CommandNotFoundException 
{

}

使用大写驼峰命名 PHP 文件,小写蛇形命名模板引擎或 web 资源文件

FooBar.php
section_layout.html.twig
index.scss

文档注释或者类型转换中,使用 bool 而不是 booleanBoolean,使用 int 而不是 integer,使用 float 而不是 doublereal

(int) $a;
(bool) $a;
(float) $a;

服务

这部分主要是介绍 symfony 框架的 services 使用规范

  • 服务的名称使用类的完全限定名,如 App\EventSubscriber\UserSubscriber;
  • 存在多个同名服务时,主要的服务使用完全限定名,其他服务使用小写下划线命名。也可以用 . 符号进行分组,例如 something.service_name, fos_user.something.service_name;
  • 参数名使用小写,环境变量名使用 %env(VARIABLE_NAME)%
  • 公共的服务添加类关联,例如关联 Symfony\Component\Something\ClassNamesomething.service_name

文档

为所有的类、方法以及函数添加 PHPDoc 注释。

根据类型来进行分组,不同类型之间空一行

 /**
 * @FooBar(1)
 * @FooBar(2)
 *
 * @var int
 */
private $var;

无返回值时,省略 @return 注释

/**
 * Configures the current command.
 */
protected function configure()
{
}

不要使用 @package@subpackage 标记。

块注释时即使只有一个标签,也不要写在同一行,比如 /** {@inheritdoc} */

/**
 * @inheritdoc
 */
function testInheritDocValid1($test)
{
}

当添加一个新的类或者大量改动一个已存在类时,也许要添加一个 @author 标记来留下个人的联系方式。

/**
 * @author Jérôme Tamarelle <jerome@tamarelle.net>
 */

示例

官方给的示例

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Acme;

/**
 * Coding standards demonstration.
 */
class FooBar
{
    const SOME_CONST = 42;

    /**
     * @var string
     */
    private $fooBar;

    /**
     * @param string $dummy Some argument description
     */
    public function __construct($dummy)
    {
        $this->fooBar = $this->transformText($dummy);
    }

    /**
     * @return string
     *
     * @deprecated
     */
    public function someDeprecatedMethod()
    {
        @trigger_error(sprintf('The %s() method is deprecated since vendor-name/package-name 2.8 and will be removed in 3.0. Use Acme\Baz::someMethod() instead.', __METHOD__), E_USER_DEPRECATED);

        return Baz::someMethod();
    }

    /**
     * Transforms the input given as first argument.
     *
     * @param bool|string $dummy   Some argument description
     * @param array       $options An options collection to be used within the transformation
     *
     * @return string|null The transformed input
     *
     * @throws \RuntimeException When an invalid option is provided
     */
    private function transformText($dummy, array $options = [])
    {
        $defaultOptions = [
            'some_default' => 'values',
            'another_default' => 'more values',
        ];

        foreach ($options as $option) {
            if (!in_array($option, $defaultOptions)) {
                throw new \RuntimeException(sprintf('Unrecognized option "%s"', $option));
            }
        }

        $mergedOptions = array_merge(
            $defaultOptions,
            $options
        );

        if (true === $dummy) {
            return null;
        }

        if ('string' === $dummy) {
            if ('values' === $mergedOptions['some_default']) {
                return substr($dummy, 0, 5);
            }

            return ucwords($dummy);
        }
    }

    /**
     * Performs some basic check for a given value.
     *
     * @param mixed $value     Some value to check against
     * @param bool  $theSwitch Some switch to control the method's flow
     *
     * @return bool|void The resultant check if $theSwitch isn't false, void otherwise
     */
    private function reverseBoolean($value = null, $theSwitch = false)
    {
        if (!$theSwitch) {
            return;
        }

        return !$value;
    }
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1

看了之后才发现自己还有一部分的不规范的书写习惯 :sweat_smile:

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!