ValueType
ValueType<T> validates or explicitly converts a value and returns it as T. PHPStan follows the generic return type through collection and union compositions.
use Derafu\Value\ValueType;
ValueType::int()->parse(12); // 12
ValueType::toInt()->parse('12.0'); // 12
ValueType::number()->parse(12.0); // 12.0, unchanged
ValueType::toNumber()->parse(12.0); // 12
Available Factories
| Factory | Contract |
|---|---|
mixed() |
Any value, including null. |
string(), int(), float(), bool() |
Exactly the indicated PHP type, without coercion. |
number() |
An existing integer or float, preserved unchanged. |
scalar() |
An existing boolean, integer, float or string. |
nonEmptyString() |
A string whose content is nonempty before and after PHP trim(). |
toInt(), toFloat(), toNumber(), toBool(), toString() |
Delegate to the corresponding ValueCaster method, excluding null. |
array() |
Any PHP array. |
map() |
An array with string keys only. |
list() |
An array with consecutive integer keys starting at zero. |
arrayOf($type) |
Any array whose values match the supplied type. |
mapOf($type) |
A string-keyed array whose values match the supplied type. |
listOf($type) |
A list whose values match the supplied type. |
literal($first, ...$others) |
One of the supplied boolean, integer or string values, compared strictly. |
instanceOf($class) |
An object of the given class or interface, returned unchanged. |
backedEnum($class) |
An existing case or an exact int/string backing value of the requested backed enum. |
dateTime() |
A DateTimeInterface, integer timestamp or non-blank date string interpreted by PHP. |
oneOf($first, ...$others) |
The first type that accepts the value. |
The primitive float() rejects integers even though ValueCaster::toFloat() can convert them. Use an explicit conversion type when conversion is intended.
Nullability
Apply nullable() to accept null in addition to a type’s ordinary values:
use Derafu\Value\ValueType;
ValueType::int()->nullable()->parse(null); // null
ValueType::toInt()->nullable()->parse(null); // null
ValueCaster preserves null directly, but conversion types reject it by default. ValueType::toInt()->parse(null) throws TypeMismatchException. This keeps nullability explicit in a composed type.
Collections
Empty collections are accepted. Lists require consecutive integer keys; maps require string keys; arbitrary arrays accept both. PHP converts some numeric string keys to integers, so ['123' => 'value'] is not a map, while ['01' => 'value'] is.
use Derafu\Value\ValueType;
$type = ValueType::arrayOf(ValueType::mapOf(ValueType::toInt()));
$type->parse([3 => ['quantity' => '12.0'], 8 => ['quantity' => '2']]);
// [3 => ['quantity' => 12], 8 => ['quantity' => 2]]
Collections preserve their keys and report nested errors with paths such as rows.8.quantity. These factories describe element types; mapOf() does not define required or optional named fields.
Unions and Literal Values
use Derafu\Value\ValueType;
$type = ValueType::oneOf(ValueType::toInt(), ValueType::string());
$type->parse('12.0'); // 12
$type->parse('text'); // 'text'
ValueType::literal('asc', 'desc')->parse('asc'); // 'asc'
ValueType::literal(false)->parse(false); // false; 0 would be rejected
Union order matters because conversion types can interpret the input. oneOf() tries the next candidate when the current candidate throws a translatable invalid-argument exception. It does not catch arbitrary runtime failures.
Backed Enums
use Derafu\Value\ValueType;
enum Status: string
{
case Pending = 'pending';
case Approved = 'approved';
}
$type = ValueType::backedEnum(Status::class);
$type->parse('approved'); // Status::Approved
$type->parse(Status::Pending); // the same enum case
Int-backed enums accept integer backing values; string-backed enums accept strings. Numeric strings are not coerced to integers, and another enum’s case is not accepted just because it has the same backing value. Unknown values throw TypeMismatchException. Passing a class that is not a backed enum to the factory throws ValueException.
Dates
dateTime() preserves an existing DateTimeInterface. An integer timestamp becomes a DateTimeImmutable using @timestamp; date text is parsed by DateTimeImmutable. Relative dates, timezones and date normalization follow PHP’s parser. Empty or invalid input throws TypeMismatchException.
use Derafu\Value\ValueType;
$date = ValueType::dateTime()->parse('2026-01-15');
$date->format('Y-m-d'); // '2026-01-15'
Custom Types and Error Context
The constructor takes a diagnostic name and a closure receiving the value, path and optional source. Return the typed result or throw ValueType::mismatch():
use Derafu\Value\ValueType;
$even = new ValueType(
'even',
static fn (mixed $value, string $path, ?string $source): int
=> is_int($value) && $value % 2 === 0
? $value
: throw ValueType::mismatch($path, 'even', $value, $source),
);
$even->parse(4, 'workers', 'settings.php'); // 4
parse($value, $path = '', $source = null) attaches a diagnostic location and origin to failures. An empty root path is displayed as $. ValueType::path($parent, $key) joins a diagnostic path with a string or integer key; it does not navigate data. See Exceptions and Translations.