LoginSignup
1
0

More than 1 year has passed since last update.

array shapes 記法は type alias で再利用できる

Last updated at Posted at 2023-02-26

PHPDoc で連想配列の内容を定義できる方法があります。

array shapes 記法と呼ばれますが、次のように定義することで、定義に合わない呼び出し方を PHPStan や Psalm で検出することができますし、 PhpStorm での補完が効くようになります。

/**
 * @param array{
 *     id: int,
 *     name: string,
 *     email: string,
 *     phone: string,
 * } $person
 */
public function setPerson(array $person)
{
    // ...
}

そこら中に配列を使うんじゃなくてちゃんとクラスを作ろうよ。というご意見もごもっともですが、配列に変換せざるを得ない場合もあるでしょ?(あると思います)
そんなときに array shapes 記法でちゃんと PHPDoc に書いてあげるといろいろと便利ですし、ドキュメントにもなりますから連想配列を使う場合にはどんどん使いたいものです。

解決したい問題

上記のような array shapes 記法で書かれた定義がいくつもの場所で出現する場合があります。

例えば person の配列を扱うメソッドがあるとどうでしょうか

/**
 * @param array<array{
 *     id: int,
 *     name: string,
 *     email: string,
 *     phone: string,
 * }> $people
 */
public function setPeople(array $people)
{
    // ...
}

このように定義を配列で囲って定義します。
さらに、people が所属する会社があるとどうでしょうか。

/**
 * @param array{
 *     id: int,
 *     companyName: string,
 *     emproyees: array<array {
 *         id: int,
 *         name: string,
 *         email: string,
 *         phone: string,
 *     }>
 * } $company
 */
public function setCompany(array $company)
{
    // ...
}

同じ定義があちこちに出てきます。
これらの定義を @return でも使っているとなると、さすがに書くのが面倒だしメンテナンスも大変です。

解決方法 (type aliases)

クラスの宣言部で type alias を定義することで、一旦定義した array shapes を使い回すことができます。

/**
 * @psalm-type PersonArray = array{
 *     id: int,
 *     name: string,
 *     email: string,
 *     phone: string,
 * }
 * @psalm-type CompanyArray = array{
 *     id: int,
 *     companyName: string,
 *     emproyees: PersonArray[],
 * }
 */
class Company
{
    /**
     * PersonArray $person
     */
    public function setPerson(array $person): void
    {
        // ...
    }

    /**
     * PersonArray[] $person
     */
    public function setPeople(array $people): void
    {
        // ...
    }

    /**
     * @param CompanyArray $company
     */
    public function setCompany(array $company): void
    {
        // ...
    }
    
    /**
     * @return CompanyArray
     */
    public function getCompany(): array
    
}

重複していた定義を綺麗にできました。
さらに CompanyArray を定義しても良いかもしれません。

また、他のクラスで定義された型エイリアスをインポートすることもできます。

/**
 * @psalm-import-type PersonArray from PersonClass
 */
class Company

@psalm-type@psalm-import-type を使っていますが、PHPStan でも同様に @phpstan-typephpstan-import-type があります。僕は PHPStan と Psalm の両方を回しているプロジェクトがありますが、@psalm-type@psalm-import-type だけをセットしていても PHPStan も認識してくれているようです。

type alias を使った場合に PhpStorm では次のちょっとした問題があります。

/**
 * @param PersonArray $person
 * @return PersonArray
 */
public function changeName(array $person, string $newName): array

ここでの PersonArray は type alias です。array の型を補足するだけのために PHPDoc を書いています。
PhpStorm はこの場合に PHPDoc comment signature is not complete という warning を与えてくれます。
$newName の定義も書きなさいと仰っています。PersonArray のところが array shapes を直に書いている場合はこの warning は出ませんので、解析が追いついていないのかもしれません。

参考文献

1
0
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
1
0