PHPDocタイプ
PHPDocの型は、PHPのネイティブ型だけでは表現しきれない配列構造、ジェネリクス、文字列制約、型ガード、セキュリティ解析のための情報を静的解析ツールに伝えるために使います。
このページでは、共通して使いやすい型、Psalm固有の型、PHPStan固有の型を分けて整理しています。PHPDoc標準、Psalm、PHPStanの対応範囲は完全には一致しないため、公開APIやライブラリではできるだけ共通構文を使い、必要な場合だけツール固有タグを使います。
使い分け
| 区分 | 用途 |
|---|---|
| 共通PHPDoc | IDE、phpDocumentor、Psalm、PHPStanで広く理解される基本型 |
| Psalm/PHPStan共通 | 両方の静的解析ツールで実用的に使える高度な型 |
| Psalm固有 | @psalm-*タグ、Psalm utility types、taint analysis |
| PHPStan固有 | @phpstan-*タグ、PHPStanの型エイリアス、PHPStan固有の追加型 |
基本型
スカラー型と特殊型
/** @param int $id */
/** @param positive-int $count */
/** @param non-negative-int $offset */
/** @param non-zero-int $delta */
/** @param float $amount */
/** @param string $name */
/** @param non-empty-string $label */
/** @param bool $enabled */
/** @return null */
/** @return true */
/** @return false */
/** @return mixed */
/** @return never */
/** @return void */
mixedは明示的に任意の型を受け入れることを表します。PHPStanでは暗黙のmixedと明示的なmixedが区別されます。
neverは、例外送出やexitなどで正常に戻らない関数を表します。PHPStanではnoreturn、never-return、never-returns、no-returnも同義として扱われます。
数値範囲
/** @param positive-int $id */
/** @param negative-int $delta */
/** @param non-positive-int $max */
/** @param non-negative-int $offset */
/** @param int-mask<1, 2, 4> $flags */
/** @param int-mask-of<Foo::INT_*> $flags */
Psalmでは範囲整数にint-range<0, 100>を使います。
/** @param int-range<0, 100> $percentage */
PHPStanでは範囲整数にint<0, 100>、int<min, 100>、int<50, max>を使います。
/** @param int<0, 100> $percentage */
文字列型
/** @param numeric-string $number */
/** @param lowercase-string $lower */
/** @param non-empty-lowercase-string $lower */
/** @param literal-string $sql */
/** @param callable-string $callable */
/** @param class-string $class */
/** @param class-string<User> $userClass */
/** @param trait-string $trait */
/** @param enum-string<Suit> $enum */
PHPStanには、さらにuppercase-string、non-falsy-string / truthy-string、non-empty-uppercase-string、non-empty-literal-string、interface-string<T>があります。配列キーとして安全な文字列を扱うためのdecimal-int-stringとnon-decimal-int-stringもあります。PHPの配列では'123'のような文字列キーが整数キーに変換されるため、array<string, mixed>を厳密に扱う場面では注意が必要です。
/** @param uppercase-string $upper */
/** @param non-empty-uppercase-string $upper */
/** @param non-falsy-string $truthy */
/** @param non-empty-literal-string $fragment */
/** @param interface-string<ServiceInterface> $service */
/** @param decimal-int-string $key */
/** @param non-decimal-int-string $safeStringKey */
オブジェクト型
/** @param object $object */
/** @param \DateTimeInterface $date */
/** @return static */
/** @return $this */
/** @return object{foo: int, bar?: string} */
/** @return object{foo: int, bar?: string}&\stdClass */
object{...}はobject shapeです。PHPStanではobject shapeのプロパティは読み取り専用として扱われ、\stdClassなどと交差させることで書き込み可能な形を表せます。
配列とリスト
汎用配列
/** @return array<string, int> */
/** @return array<int, User> */
/** @return non-empty-array<string, User> */
/** @return iterable<int, User> */
Type[]はarray<array-key, Type>相当の古い表記です。新しいコードでは、キー型を明示できるarray<TKey, TValue>を優先します。
/** @param User[] $users */
/** @param array<int, User> $users */
PHPStanではassociative-arrayも基本型として使えます。
/** @return associative-array */
リスト
list<T>は0から始まる連続した整数キーの配列です。
/** @param list<string> $names */
/** @return non-empty-list<User> */
PsalmとPHPStanはlist shapeも扱えます。
/** @return list{string, int} */
PHPStanではnon-empty-list{string, int}のように、non-empty指定とshape構文を組み合わせることもできます。
Array shape
Array shapeはキーごとに異なる型を表します。
/**
* @return array{
* id: positive-int,
* name: non-empty-string,
* email?: non-empty-string,
* roles: list<non-empty-string>
* }
*/
function userProfile(): array;
Psalmはarray{..., ...}でopen shapeを表し、PHPStanは...<K, V>(や...<T>のようなvariadic list shape)で型付きunsealed shapeを表せます。
/** @param array{verbose: bool, ...} $options */
/** @param array{foo: int, ...<string, int>} $data */
/** @return list{string, int, ...<bool>} */
PHPStanではsealed array shapeの扱いが厳密です。extra keysを許す意図がある場合は、unsealed shapeを明示します。
複合型
Union、Intersection、括弧
/** @param int|string $id */
/** @return User|null */
/** @param Countable&Traversable $collection */
/** @param (A&B)|C $value */
値型と定数型
/** @return 'success'|'error'|'pending' */
/** @return 200|400|500 */
/** @param Foo::STATUS_* $status */
/** @param Foo::* $constant */
Callable
/** @param callable(int, string): bool $callback */
/** @param callable(string &$value): void $normalizer */
/** @param callable(float ...$values): int|null $aggregate */
/** @param Closure(User): string $formatter */
/** @param pure-callable(User): string $formatter */
/** @param pure-Closure(User): string $formatter */
PHPStanでは@param-closure-thisでクロージャ内の$thisを指定できます。
/**
* @param Closure(): void $callback
* @param-closure-this User $callback
*/
function withUser(Closure $callback): void;
ジェネリクス
関数テンプレート
/**
* @template T
* @param list<T> $items
* @param callable(T): bool $predicate
* @return list<T>
*/
function filter(array $items, callable $predicate): array;
クラステンプレート
/**
* @template TKey of array-key
* @template TValue
* @implements IteratorAggregate<TKey, TValue>
*/
final class Collection implements IteratorAggregate
{
/** @var array<TKey, TValue> */
private array $items = [];
/** @return Traversable<TKey, TValue> */
public function getIterator(): Traversable
{
yield from $this->items;
}
}
PsalmとPHPStanは@template-covariantと@template-contravariantを扱えます。PHPStanは利用箇所側のCollection<covariant Animal>、Collection<contravariant Dog>や、型引数を読み書き制限付きで任意にするCollection<*>も扱います。
条件付き型
/**
* @template T of int|array<int>
* @param T $id
* @return (T is int ? User : list<User>)
*/
function fetch(int|array $id): User|array;
PHPStanでは否定条件も扱えます。
/**
* @return ($value is not null ? string : never)
*/
function stringify(mixed $value): string;
型演算子
key-of / value-of
/**
* @param key-of<User::FIELDS> $field
* @return value-of<User::FIELDS>
*/
function fieldValue(string $field): string|int;
value-of<BackedEnum>はPHPStanでBackedEnumの値型を取り出す用途にも使えます。
/** @param value-of<Suit> $suit */
function selectSuit(string $suit): void;
Offset access
/**
* @template T of array<string, mixed>
* @template K of key-of<T>
* @param T $data
* @param K $key
* @return T[K]
*/
function get(array $data, string $key): mixed
{
return $data[$key];
}
Psalm utility types
Psalmはproperties-of<T>、public-properties-of<T>、protected-properties-of<T>、private-properties-of<T>、class-string-map<T of Foo, T>、変数テンプレートなどのutility typesを提供します。詳細はPHPDoc ユーティリティ型を参照してください。
/**
* @template T of object
* @param class-string-map<T, T> $instances
* @param class-string<T> $class
* @return T
*/
function instance(array $instances, string $class): object
{
return $instances[$class];
}
PHPStan utility types
PHPStanはtemplate-typeで渡されたオブジェクトからtemplate型を取得し、newでclass-string<T>からオブジェクト型を作れます。
/**
* @template T of object
* @param class-string<T> $class
* @return new<T>
*/
function create(string $class): object
{
return new $class();
}
型エイリアス
Psalmの型エイリアス
/**
* @psalm-type UserId = positive-int
* @psalm-type UserData = array{id: UserId, name: non-empty-string}
*/
final class UserTypes {}
/**
* @psalm-import-type UserData from UserTypes
* @param UserData $user
*/
function saveUser(array $user): void {}
PHPStanの型エイリアス
/**
* @phpstan-type UserId positive-int
* @phpstan-type UserData array{id: UserId, name: non-empty-string}
*/
final class UserTypes {}
/**
* @phpstan-import-type UserData from UserTypes
* @param UserData $user
*/
function saveUser(array $user): void {}
PHPStanはphpstan.neonのtypeAliasesでグローバル型エイリアスも定義できます。
parameters:
typeAliases:
UserId: positive-int
UserData: 'array{id: UserId, name: non-empty-string}'
Assert / type guard
PsalmのAssert
/**
* @psalm-assert non-empty-string $value
*/
function assertNonEmptyString(mixed $value): void
{
if (! is_string($value) || $value === '') {
throw new InvalidArgumentException();
}
}
/**
* @psalm-assert-if-true User $value
*/
function isUser(mixed $value): bool
{
return $value instanceof User;
}
Psalmは@psalm-if-this-isと@psalm-this-outで、メソッド呼び出し後の$thisの型も表せます。
PHPStanのAssert
/**
* @phpstan-assert non-empty-string $value
*/
function assertNonEmptyString(mixed $value): void;
/**
* @phpstan-assert-if-true User $value
*/
function isUser(mixed $value): bool;
PHPStanは@phpstan-self-outと@phpstan-this-outで、メソッド呼び出し後の現在オブジェクトの型を変化させられます。
/**
* @template TValue
*/
final class Bag
{
/**
* @template TItem
* @param TItem $item
* @phpstan-self-out self<TValue|TItem>
*/
public function add(mixed $item): void {}
}
参照渡しの出力型
PsalmとPHPStanは@param-outで、参照渡しパラメータの呼び出し後の型を表せます。Psalm固有タグとして@psalm-param-outも使えます。
/**
* @param-out non-empty-string $value
*/
function fillDefault(?string &$value): void
{
$value ??= 'default';
}
不変性と副作用
Psalmでは副作用や不変性を明示できます。
/**
* @psalm-immutable
*/
final class Point
{
public function __construct(
public float $x,
public float $y
) {}
/** @psalm-mutation-free */
public function move(float $x, float $y): self
{
return new self($this->x + $x, $this->y + $y);
}
}
主なタグ:
| タグ | 意味 |
|---|---|
@psalm-pure |
入力だけに依存する純粋関数 |
@psalm-impure |
副作用がある関数 |
@psalm-mutation-free |
自身も外部状態も変更しないメソッド |
@psalm-external-mutation-free |
外部状態を変更しないメソッド |
@psalm-immutable |
不変クラス |
@psalm-readonly / @readonly |
読み取り専用プロパティ |
@psalm-allow-private-mutation |
private文脈だけで変更可能 |
PHPStanでは@phpstan-pureと@phpstan-impureが使えます。読み取り専用でprivate変更を許す場合は@phpstan-allow-private-mutationや@phpstan-readonly-allow-private-mutationを使います。
セキュリティ解析
Psalmのtaint analysisでは、入力源、危険な出力先、escape処理、flowをPHPDocで表現できます。
/**
* @psalm-taint-source input
*/
function userInput(): string
{
return $_GET['q'] ?? '';
}
/**
* @psalm-taint-sink sql $query
*/
function query(string $query): void {}
/**
* @psalm-taint-escape sql
*/
function escapeSql(string $value): string
{
return addslashes($value);
}
主なタグ:
| タグ | 用途 |
|---|---|
@psalm-taint-source <type> |
信頼できない入力源 |
@psalm-taint-sink <type> <param> |
危険な出力先 |
@psalm-taint-escape <type> |
taintを除去する処理 |
@psalm-taint-unescape <type> |
escape済みデータを再びtaint扱いにする |
@psalm-taint-specialize |
関数やクラスでtaintを特殊化する |
@psalm-flow (...) -> return |
明示的なtaint flow |
デバッグと検証用タグ
/** @psalm-trace $value */
$value = userInput();
/** @psalm-check-type $value = non-empty-string */
$value = 'BEAR';
/** @psalm-check-type-exact $value = 'BEAR' */
$value = 'BEAR';
これらはドキュメント用というより、Psalmの推論結果を確認するための開発支援タグです。
BEAR.Sundayでの推奨
- ネイティブ型で表せるものはPHPの型宣言に書きます。
- 配列の要素型、array shape、list、ジェネリクス、型エイリアスはPHPDocに書きます。
- 公開APIではPsalm/PHPStan両方で理解しやすい構文を優先します。
- Psalm固有の解析には
@psalm-*、PHPStan固有の解析には@phpstan-*を使い、意図的に分けます。 - shapeが大きくなりすぎる場合は、array shapeよりDTO、Value Object、Entityを検討します。
- SQL、HTML、ファイルパス、コマンドなどのセキュリティ境界では、
literal-string、taint annotation、専用のSemantic Typeを組み合わせます。
互換注意点
| 項目 | 注意 |
|---|---|
int-range / int<min, max> |
Psalmはint-range、PHPStanはint<min, max>を使います。 |
@psalm-type / @phpstan-type |
ツール固有です。両方使う場合は同じ意味で二重定義します。 |
properties-of |
Psalm utility typeです。PHPStan向けには別表現を検討します。 |
| unsealed shape | extra keysを許す意図がある場合に明示します。 |
literal-string |
セキュリティ上有用ですが、通常のstringとは別物です。SQLやテンプレート断片で使います。 |
array<string, T> |
PHPの配列キー変換により、整数文字列キーがintになることがあります。PHPStanのnon-decimal-int-stringを検討します。 |