LoginSignup
2
1

More than 1 year has passed since last update.

Array Shapes/ジェネリクス記法とPHPStanを使って配列要素の型をチェックする

Last updated at Posted at 2023-01-25

PHPの配列要素の型がチェックできない問題

この、PHPの配列要素の型をチェックできない問題ですが、みなさん一度は思われたことがあるのではないでしょうか?関数やメソッドの引数や返り値、オブジェクトのプロパティにについては型はつけやすくなりましたが、配列の内部構造はまだまだです

例えば関数の戻り値にarrayを指定している場合、配列以外の型を持った値を返そうとするとエラーになりますが、配列の要素に関しては何が入ってこようとエラーは出ません。そのため、思わぬバグに繋がってしまうことがあるのです

そこで本記事ではその解決策となるテクニックをご紹介していきます

結論:Array Shapes/旧PSR-5形式のジェネリクス記法で記載し、PHPStanを使用して解析する

早速結論ですが、PHPDocのArray Shapes記法とPHPStanを組み合わせて配列要素の型をチェックします

ざっくりと言うと、Array Shapes/旧PSR-5形式のジェネリクス記法でDocコメントを記載し実装を進め、その後に静的解析(PHPstan)を実行することで、型チェックをするイメージです

ケーススタディ

ややこしい話をするより実際にコードをいくつか見ていきます

旧PSR-5形式のジェネリクス記法

まずはジェネリクス記法から。下記コードのようにarray<int, User>とすることで、キーと値の型を指定します

/**
 * @return array<int, User>
 */
function getUsers(): array
{
    return $this->users;
}

また、キーの指定が必要ない場合は

/**
 * @return array<User>
 */
function getUsers(): array
{
    return $this->users;
}

のように記載します。

Array Shapes記法

続いてArray Shapes記法についてです。記法が複数出てきて混乱するかもしれないですが、どちらを使っても、併用しても問題ありあせん(基本的には併用することになるかと思います)

また、仕様については下記サイトに記載してあります

早速例題ですが、連想配列は以下のように型をつけることができます。idnameisJapaneseがキー名になっていて、その隣に型を記載します

/**
* @return array{id: UserId, name: string, isJapanese: bool}
*/
public function getArray(): array
{
    return [
        'id'         => new UserId(1),
        'name'       => '山田花子',
        'isJapanese' => true
    ];
}

nullを許容する際は、address: ?stringのように、値の先頭に?をつけます

/**
* @return array{id: UserId, name: string, isJapanese: bool, address: ?string}
*/
public function getArray(): array
{
    return [
        'id'         => new UserId(1),
        'name'       => '山田花子',
        'isJapanese' => true,
        'address'    => null
    ];
}

上記の例ではaddressの値はnullが入りえますが、addressを省略することはできません。キーが省略される可能性がある場合は、address?: stringのように、キー名の最後に?をつけます

/**
* @return array{id: UserId, name: string, isJapanese: bool, address?: string}
*/
public function getArray(): array
{
    return [
        'id'         => new UserId(1),
        'name'       => '山田花子',
        'isJapanese' => true
    ];
}

nullを許容とキーを省略を併用したい場合は、address?: ?stringと記載してください

PHPStanを実行する

ここまでで準備は整いました。あとはPHPStanを実行することで、タインプヒントのエラーを発見することができます

また、PHPStanのlevelについてですが、

6.report missing typehints.

下記サイトにも記載してある通り、Level6からタイプヒントのエラーをレポートするようになるので、PHPStanのlevelは6に設定するようにしましょう

おわりに

以上で、配列要素の型チェックができるようになります

プラスアルファとしては、PHPStanをCI(継続的インテグレーション)に組み込み、自動的にこのチェックが行われるようにしましょう。機会があればまた記事にしたいと思います

何かご指摘やご意見があればコメントお願いします!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1