PHP 規範 - Symfony 程式碼規範

心智極客發表於2019-11-06

注:規範主要來源於 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 協議》,轉載必須註明作者和本文連結

相關文章