sebastian/type
sebastian/type provides lightweight value objects that model PHP’s type system. Useful for tools and libraries that need to represent, compare, and work with types (including complex and composite types) in a consistent, structured way.
Install as a dev dependency: composer require --dev sebastian/type. Focus first on ReflectionMapper and the Type hierarchy (ObjectType, UnionType, IntersectionType, etc.). The primary use case is building or extending static analysis tools—e.g., writing a custom PHPStan rule that checks for missing @return annotations by mapping ReflectionMethod to a Type object via ReflectionMapper::fromFunctionLikeType($method->getReturnType()). Start by reviewing src/Type.php and src/ReflectionMapper.php to see how PHP’s reflection API is normalized into composable value objects.
For class alias resolution (newly fixed in v7.0.1), test with classes like stdClass vs array or DateTimeImmutable vs DateTime to verify assignability checks now account for aliases (e.g., ReflectionMapper::fromType(new \ReflectionNamedType('DateTime'))->isAssignableFrom(ReflectionMapper::fromType(new \ReflectionNamedType('DateTimeImmutable')))).
ReflectionMapper::fromPropertyType() (added in v5.1.0) to convert ReflectionProperty::getType() into Type instances for enforcing field-level constraints (e.g., ensuring all DTO properties are typed as scalar or nullable).Type::equals() and is_subtype_of() to detect incompatible overrides (e.g., parent::save(): void vs child::save(): bool). Now verify class alias assignability (e.g., DateTimeImmutable as a DateTime substitute) using Type::isAssignableFrom().Type objects to strings (via toString()) when scaffolding API clients or OpenAPI specs from reflection data—especially useful for union/intersection types. Test with aliased classes (e.g., DateTimeInterface implementations).Type::isCompatibleWith() (e.g., verify that a function returning int|float is compatible with float|int). For class aliases, use Type::isAssignableFrom() to validate inheritance/substitution hierarchies.ReflectionMapper::fromType() on aliased class names (e.g., 'array' → ArrayObject or stdClass → object). Example:
$arrayType = ReflectionMapper::fromType(new \ReflectionNamedType('array'));
$objectType = ReflectionMapper::fromType(new \ReflectionNamedType('stdClass'));
$arrayType->isAssignableFrom($objectType); // Now returns `false` (correctly)
^6.0. Verify with composer show sebastian/type—6.0.x supports up to PHP 8.3.iterable edge cases: Though fixed in 5.1.1+/6.0.2+, ReflectionMapper::fromType() historically mishandled unions like iterable|ArrayObject. Always test with edge cases (e.g., iterable|Traversable|Closure).DateTimeImmutable vs DateTime). However, union/intersection types with aliases (e.g., DateTime|DateTimeImmutable) may still require explicit normalization. Test with:
$union = UnionType::fromTypes([
ReflectionMapper::fromType(new \ReflectionNamedType('DateTime')),
ReflectionMapper::fromType(new \ReflectionNamedType('DateTimeImmutable')),
]);
$union->isAssignableFrom(ReflectionMapper::fromType(new \ReflectionNamedType('DateTime'))); // Now accurate
int, string, object, unions/intersections). It does not support class-string, trait aliases, or custom user-defined types—extend Type carefully for domain-specific needs.Type objects are value objects—no setters, no mutation. If your code mutates types (e.g., appending null to a union), create a new UnionType instance.var_dump($type) on a Type instance to see its internal structure (e.g., ObjectType shows the FQCN; UnionType lists all components). Pair with Xdebug to trace reflection mapping in complex code. For alias issues, inspect the resolved class name via:
var_dump($type->getClassName()); // Shows the actual FQCN after alias resolution
Type::equals() for alias comparison, prefer Type::isAssignableFrom() + Type::isAssignableTo() for stricter checks (e.g., DateTimeImmutable is assignable to DateTime but not equal).How can I help you explore Laravel packages today?