PSR-12まとめ：PHPコーディングスタイルの標準化

:::note 
<details><summary>AI要約</summary>

- PSR-12はPHPのコーディングスタイルを標準化し、コードの可読性と保守性を向上させるためのガイドラインです
- PHPファイルはUnixスタイルの改行（LF）を使用し、空白行ではなく有効なコードやコメントで終了する必要があります
- キーワードは小文字で記述し、引数や戻り値には一貫して型宣言を使用します
- クラスやメソッドの左中括弧 { は次の行に置き、クラスプロパティにはアクセス修飾子（デフォルトはprivate）を明示します。
- 演算子、条件演算子、クロージャーなどの書き方には特定のスタイルルールがあり、コード例を参照して適切に記述します
</details>
:::
## 目的
開発メンバーが書いたコードを読む際の脳内負荷を減らすこと
一定のコーディング規則があれば、コードの読みやすさが向上します
そんなコーディング規則の１つでもあるPSR-12を超ざっくりと説明していきます

## 諸注意
生成AIで要約をしていますので原文の見出しとは異なったまとめになっております。
なお、主観的な感覚で割愛している部分もありますので詳しい内容な原文をご参考ください。

## 基本的なコーディングスタイル

### ファイル構造

- 全てのPHPファイルは改行する際に改行コードをUnix LF（ラインフィード）を行末でのみ使用する必要があります
    - PSR-12では、コードの一貫性と移植性を保つために、全てのPHPファイルでUnixスタイルのLF（ラインフィード）を使用することを推奨しています。これにより、異なる開発環境間でファイルをやり取りする際に、改行コードの違いによる問題を防ぐことができます
- 全てのPHPファイルは、空白以外の行で終わり、単一の LFで終了する必要があります
    - PHPファイルの最後の行が、空白（スペースやタブ）だけの行で終わるのではなく、有効なコードやコメントなどの内容を含む行で終わること
- PHPを含むファイルでは、終了タグを省略する必要があります

### インデントと行の長さ
- 1行の長さは80文字が推奨、最大120文字まで許容範囲になります
    - なお、厳しい制限はないので場合によってここは変更するのもアリです
- 行末に空白を入れてはいけません
- 明示的に禁止されている場合を除き、読みやすさを向上させ、コードの関連ブロックを示すために、空白行を追加できます
    - 良い例：
```php
<?php

$number = 10;
echo $number;
$number++;
```

- 悪い例：

```php
<?php

$number = 10; echo $number; $number++;
```

## キーワードと型
- キーワードはすべて小文字で書く（例: if, else, while)
- 引数と戻り値には一貫して型宣言を使用する
    - ただし、短い形式を使用する必要がある
    - 「boolean」の代わりに「bool」、「integer」の代わりに「int」など

## 宣言文、名前空間、インポート文

 ### ヘッダー構成要素の順序とルール
1. PHP開始タグ
    - ファイルの最初に書かれ、他のステートメントを含まない独自の行にします
        - 例: <?php

1. ファイルレベルのDocBlock
    - ファイル全体の説明や著作権情報を記載します
    - 例:
```php
/**
 * This file contains an example of coding styles.
 */
```

1. 宣言ステートメント
    - 厳密な型指定などを宣言します
    - 例: `declare(strict_types=1);`

1. 名前空間宣言
    - ファイルが属する名前空間を宣言します
    - 例: `namespace Vendor\Package;`

1. useインポート文
    - クラス、関数、定数のインポートを行う。各インポートタイプごとにブロックを区別し、1つ以上の空白行で区切ります
    - クラスのインポート：
```php
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use Vendor\Package\AnotherNamespace\ClassE as E;
```
    - 関数のインポート
```php
use function Vendor\Package\{functionA, functionB, functionC};
use function Another\Vendor\functionD;
```
    - 定数のインポート：
```php
use const Vendor\Package\{CONSTANT_A, CONSTANT_B, CONSTANT_C};
use const Another\Vendor\CONSTANT_D;

```

## クラスとメソッド
### クラス
- 1つのファイルに1つのクラスを定義します
- クラスやメソッドの左中括弧は次の行に置きます
- クラスプロパティにはアクセス修飾子を明示し、デフォルトはprivateにします

具体例
```php
<?php

declare(strict_types=1);

namespace ExampleNamespace;

use SomeDependency;

class ExampleClass
{
    private int $property1;
    private string $property2;

    public function __construct(int $property1, string $property2)
    {
        $this->property1 = $property1;
        $this->property2 = $property2;
    }

    public function getProperty1(): int
    {
        return $this->property1;
    }

    public function setProperty1(int $property1): void
    {
        $this->property1 = $property1;
    }

    public function getProperty2(): string
    {
        return $this->property2;
    }

    public function setProperty2(string $property2): void
    {
        $this->property2 = $property2;
    }
}
```

### メソッド
- メソッドの左中括弧 { も次の行に記述します
- メソッドにはアクセス修飾子（public, protected, private）を必ず指定します

具体例
```php
<?php

/**
 * This file contains an example of coding styles.
 */

declare(strict_types=1);

namespace Vendor\Package;

use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use Vendor\Package\AnotherNamespace\ClassE as E;

use function Vendor\Package\{functionA, functionB, functionC};
use function Another\Vendor\functionD;

use const Vendor\Package\{CONSTANT_A, CONSTANT_B, CONSTANT_C};
use const Another\Vendor\CONSTANT_D;

/**
 * FooBar is an example class.
 */
class FooBar
{
    private int $value;

    public function __construct(int $initialValue)
    {
        $this->value = $initialValue;
    }

    public function getValue(): int
    {
        return $this->value;
    }

    public function setValue(int $value): void
    {
        $this->value = $value;
    }
    
    protected function calculate(int $a, int $b): int
    {
        return $a + $b;
    }
}
```

### 関数とメソッドの書き方
- 引数リスト、戻り値の型、カッコの間にスペースを入れません
- 関数と引数リストの間にスペースを入れません

具体例
```php
<?php

function add(int $a, int $b): int
{
    return $a + $b;
}

class Math
{
    public function multiply(int $a, int $b): int
    {
        return $a * $b;
    }
}

$math = new Math();
echo add(5, 3); // 8
echo $math->multiply(5, 3); // 15
```

## 制御構造
- キーワードの後にスペースを入れる
- 左中括弧 { は次の行に記述します
- コントロール構造の内部はインデントします

具体例
```php
<?php

if ($a > $b) {
    echo "$a is greater than $b";
} elseif ($a === $b) {
    echo "$a is equal to $b";
} else {
    echo "$a is less than $b";
}

for ($i = 0; $i < 10; $i++) {
    echo $i;
}

while ($condition) {
    // loop body
}
```

## 空白行とコメント
### 空白行
- ファイルの終わりに1つの空白行を入れます
- メソッドの間、クラスのプロパティの間には１つの空白行を挿入します
### コメント
- コメントは一貫したスタイルで書き、コードの意図を明確にします

## 演算子
### 単項演算子
- 増分/減分演算子は、演算子とオペランドの間にスペースを入れません
```php
$i++;
++$j;
```
- 型キャスト演算子は、括弧内にスペースを入れません

```php
$intValue = (int) $input;
```

### 二項演算子
- 二項演算子、比較演算子、代入演算子などの前後には、少なくとも1つのスペースを入れます
```php
if ($a === $b) {
    $foo = $bar ?? $a ?? $b;
} elseif ($a > $b) {
    $foo = $a + $b * $c;
}
```

### 条件演算子
- 条件演算子（単に三項演算子とも呼ばれる）の「？」と「：」の前後にスペースを入れます
```php
$variable = $foo ? 'foo' : 'bar';
```
- 中央のオペランドが省略される場合、他の比較演算子と同じスタイル規則に従います
```php
$variable = $foo ?: 'bar';
```

## クロージャー
- `function`キーワードの後とuseキーワードの前後にスペースを入れる
- 左中括弧 { は同じ行に配置し、右中括弧 } は本文に続く次の行に配置する
- 引数リストや変数リストの括弧の間にスペースを入れない
- コンマの前にスペースを入れず、後に1つのスペースを入れる
- デフォルト値を持つ引数はリストの最後に置く
- 戻り値の型がある場合、通常の関数とメソッドの規則に従う

具体例
```php
<?php

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

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};

$closureWithArgsVarsAndReturn = function ($arg1, $arg2) use ($var1, $var2): bool {
    // body
};
```

クロージャーが関数やメソッドの引数として使用される場合も同様のスタイル規則を適用します

```php
<?php

$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);
```

## まとめ
ちょっと長いし難しい部分もあるけど上記のようにコーディングスタイルを標準化してくれたら書き方に迷わなくて済みますね
悩んでる時間って案外長いんですよね。。。気づいたら１時間取られてたり。。。
その時間を節約できると考えたら改めて一読しておくのも良いなと思いました

## 参考文献
https://www.php-fig.org/psr/psr-12/

https://www.ritolab.com/posts/208

https://qiita.com/rana_kualu/items/28f169bb3eadc6f9e3f3