PHPDoc Utility Types

Utility types are type operators that derive keys, values, property maps, or indexed value types from existing types. For the broader PHPDoc type reference, see PHPDoc Types.

Some types, such as properties-of and class-string-map, are Psalm-specific, so check the analyzer you use before adopting them.

key-of

key-of<T> extracts the key type from an array type, array shape, or constant array.

final class User
{
    public const FIELDS = [
        'id' => 1,
        'name' => 2,
        'email' => 3,
    ];
}

/**
 * @param key-of<User::FIELDS> $field
 */
function selectField(string $field): void {}

selectField('name'); // OK
selectField('age');  // static analysis error

When combined with templates, constrain T to an array type.

/**
 * @template T of array
 * @param T $data
 * @return list<key-of<T>>
 */
function keys(array $data): array
{
    return array_keys($data);
}

value-of

value-of<T> extracts the value type. PHPStan also supports value-of<BackedEnum>.

enum Suit: string
{
    case Hearts = 'H';
    case Spades = 'S';
}

/**
 * @param value-of<Suit> $suit
 */
function chooseSuit(string $suit): void {}

With constant arrays, it extracts literal value types.

/**
 * @param value-of<User::FIELDS> $fieldId
 */
function byFieldId(int $fieldId): void {}

T[K]

T[K] represents the value type of array type T at key K. It preserves the relationship between a key and its value in array shapes and configuration arrays.

/**
 * @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];
}

$config = [
    'debug' => true,
    'name' => 'BEAR.Sunday',
];

$debug = get($config, 'debug'); // bool
$name = get($config, 'name');   // string

properties-of (Psalm)

properties-of<T> represents a class’ properties as an array-shape-like map of property names to property types.

final class Profile
{
    public int $id;
    public string $name;
    protected string $token;
}

/**
 * @param Profile $profile
 * @param key-of<public-properties-of<Profile>> $property
 * @return value-of<public-properties-of<Profile>>
 */
function publicProperty(Profile $profile, string $property): mixed
{
    return $profile->$property;
}

Psalm provides these variants:

Type Scope
properties-of<T> All properties
public-properties-of<T> Public properties
protected-properties-of<T> Protected properties
private-properties-of<T> Private properties

class-string-map<T of Foo, T> (Psalm)

class-string-map<T of Foo, T> describes an array whose keys are class-name strings and whose values are instances of the corresponding classes.

interface Handler {}

final class CreateHandler implements Handler {}
final class DeleteHandler implements Handler {}

/**
 * @template T of Handler
 * @param class-string-map<T, T> $handlers
 * @param class-string<T> $class
 * @return T
 */
function handler(array $handlers, string $class): Handler
{
    return $handlers[$class];
}

This is useful for containers, factories, and registries.

template-type and new (PHPStan)

PHPStan supports template-type to extract a template type from an object argument, and new to represent the object type created from a class-string<T>.

/**
 * @template T of object
 * @param class-string<T> $class
 * @return new<T>
 */
function create(string $class): object
{
    return new $class();
}

new<T> is useful when a factory or container returns an instance related to a class-name string.

Combining with Type Aliases

Complex utility types are easier to read when named with type aliases.

/**
 * @psalm-type UserProfile = array{
 *   id: positive-int,
 *   name: non-empty-string,
 *   roles: list<non-empty-string>
 * }
 */
final class UserTypes {}

/**
 * @psalm-import-type UserProfile from UserTypes
 * @param UserProfile $profile
 * @param key-of<UserProfile> $property
 * @return value-of<UserProfile>
 */
function profileValue(array $profile, string $property): mixed
{
    return $profile[$property];
}

For PHPStan, use @phpstan-type and @phpstan-import-type.

Compatibility Notes

Type Psalm PHPStan Notes
key-of<T> Supported Supported Useful with arrays, array shapes, and constant arrays
value-of<T> Supported Supported PHPStan also supports backed enums
T[K] Supported Supported Offset access
properties-of<T> Supported Not supported Psalm utility type
class-string-map<T of Foo, T> Supported Not supported Psalm utility type
template-type Not supported Supported PHPStan utility type
new<T> Not supported Supported PHPStan utility type

References