There are few aspects of specifying type of expression in PHP:
- The most exact specification of the type (we assume it's in psalm syntax):
array<int,DateTime|null>
- The sequence of run time assertions:
assert($records instanceof array<int,DateTime|null>)
- The type hint for static analysers (which is psalm at the moment):
(array<int,DateTime|null>) $records
- The ability to derive types without string manipulation:
array<int,DateTime|null> || null
- The ability to cast when it's safe, i.e. falsey should cast to false, etc.
This library provides the basic building blocks for type specifications. For example, the following expression:
$type = _map(
_int(),
_union(
_class(DateTime::class),
_null()
)
)
creates an object of type Type<array<int,DateTime|null>>
.
Asserting at run time, that the type of $records
is array<int,DateTime|null>>
:
$type->assert($records);
Cast $records
to array<int,DateTime|null>>
and throw an exception when $records
cannot be cast to array<int,DateTime|null>>
:
return $type->cast($records);
Combine type with other types, for example, making it nullable array<int,DateTime|null>>|null
:
_union($type, _null())
Object like arrays require more leg work. For example the type array{id:int,name:string,valid?:bool}
corresponds to this construct:
/** @var Type<array{id:int,name:string,valid?:bool}> */
$type = _object_like([
'id' => _int(),
'name' => _string(),
'valid?' => _bool()
]);
Quite a mouthful. Also, note the required @var
as psalm currently have no support for dependent types.
If you want to assert types matching your PHPDoc you can use the type parser (WiP):
/** @var Type<array{id:int}> */
$type = Type::of('array{id:int}');
assert($type->matches($record));
- Move completely to PHPStan parsed including docblock
- Add union and intersection types
- Support for enums
- Support for non-empty-* types
- Support for tuples as int
array{int,string}
- Support for iterable|self|static|class-string
- Better support for callables
- Add PHPStan to QA pipeline