Laravel PHPStan の配列型エラー

# 概要

- PHP Laravelにて開発中にPHPStanにて配列型のエラーが出たので回避方法をまとめてみる。

# エラーが発生したコード

- 下記のコードはlaravel-dataというライブラリのリクエストクラスのバリデーションルール定義クラスの記載の一部である。
- 下記のコードがなんのコードであるかは今回のエラーに関係はなく、定義されているrules()関数の戻り値の型がarrayとして指定されていることに問題がある。

    ```php
    use Illuminate\Validation\Rule;

    public static function rules(): array
    {
        return [
            'foo_inf_value' => [
                Rule::in([10, 11])
            ]
        ];
    }
    ```

# 出力されたエラー

- PHPStanを実行したところ下記のエラーが出力された。

    ```
    Method FooClass::rules() return type has no value type specified in iterable type array.
    ```

- 和訳すると下記の様になる。

    ```
    メソッド Foo::rules（）の戻り型には、反復可能な型配列で指定された値型がありません。
    ```

# 解決の結論

- 下記のように記載すれば良い

    ```php
    use Illuminate\Validation\Rule;
    use Illuminate\Validation\Rules\In;

    /** @return array<string, array<int, In>> */
    public static function rules(): array
    {
        return [
            'foo_inf_value' => [
                Rule::in([10, 11])
            ]
        ];
    }
    ```

# 解決までの経緯

- エラーの内容は下記にまとまっていた。
    - [https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type](https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type)
- どうやら当該の配列がどのような構成になっているか（中にどのような値が格納されているか）が指定されていないためのエラーのようだ。
- このエラーはPHPStanのレベル6によって報告されるらしい。
- 今回のエラー対象は配列のため下記を読んで見る。
    - [https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type#arrays](https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type#arrays)
- PHPDocを使ってPHPStanに配列の中の構造を指定してあげれば良いようだ。
- とりあえず下記のように記載してPHPStanで解析してみた。

    ```php
    use Illuminate\Validation\Rule;

    /** @return array<string> */
    public static function rules(): array
    {
        return [
            'foo_inf_value' => [
                Rule::in([10, 11])
            ]
        ];
    }
    ```

- 下記のようなエラーが帰ってきた。

    ```
    Method FooClass::rules() should return array<string> but returns array<string, array<int, Illuminate\Validation\Rules\In>>.
    ```

- 和訳すると下記の様になる。

    ```
    メソッドFooClass::rules（）はarray <string>を返す必要がありますが、array <string、array <int、Illuminate \ Validation \ Rules \In>>を返します。
    ```

- array内部の構造の指定が誤っている模様である。エラー文に表示されている現在の構造をコードで指定してあげる。

    ```php
    use Illuminate\Validation\Rule;

    /** @return array<string, array<int, Illuminate\Validation\Rules\In>> */
    public static function rules(): array
    {
        return [
            'foo_inf_value' => [
                Rule::in([10, 11])
            ]
        ];
    }
    ```

- Inクラスの名前解決がうまくできていない模様なので下記のようにuseでInクラスを名前解決してあげて下記のように書き直した。

    ```php
    use Illuminate\Validation\Rule;
    use Illuminate\Validation\Rules\In;

    /** @return array<string, array<int, In>> */
    public static function rules(): array
    {
        return [
            'foo_inf_value' => [
                Rule::in([10, 11])
            ]
        ];
    }
    ```    

- エラーは発生しなくなった。問題なくPHPStanにarray内の構造を示してあげる事ができた模様。
- ジェネリクス（ジェネリック）が絡んでいるらしい。なんとなく理解しているけどまだよくわかりきっていないのでどこかでジェネリクスについてもまとめたいところ。
    - [https://phpstan.org/blog/generics-in-php-using-phpdocs](https://phpstan.org/blog/generics-in-php-using-phpdocs)

# 追記

- 先輩エンジニアさんに下記の様に記載すると汎用性が高くて良いかもですと教えていただきました。。！（教えていただきありがとうございます！）

    ```php
    /** @return array<mixed> */
    ```

# 参考文献

- [https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type#arrays](https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type#arrays)
- [https://phpstan.org/blog/generics-in-php-using-phpdocs](https://phpstan.org/blog/generics-in-php-using-phpdocs)