Type Casting
The library automatically casts input values based on property types, with optional #[Cast] and #[Caster] attributes for explicit control.
Automatic Casting (driven by declared type)
When no #[Cast] or #[Caster] is specified, values are cast based on the property type:
public int $count; // Cast to int
public float $price; // Cast to float
public bool $active; // Cast to bool
public string $name; // Cast to string
public array $tags; // Cast to arrayExplicit Casting (#[Cast])
Use #[Cast] for built-in casts when the property type alone isn't enough (e.g. DateTime with a format):
use Solo\RequestHandler\Attributes\Cast;
#[Cast('int')]
public int $quantity;
#[Cast('float')]
public float $amount;
#[Cast('bool')]
public bool $enabled;
#[Cast('array')]
public array $items;Built-in Type Casting
Integer
$caster->cast('int', '123'); // 123
$caster->cast('int', true); // 1
$caster->cast('int', false); // 0
$caster->cast('int', 'abc'); // 0Float
$caster->cast('float', '12.34'); // 12.34
$caster->cast('float', '100'); // 100.0
$caster->cast('float', true); // 1.0Boolean
| Input | Result |
|---|---|
true, "true", "1", "on", "yes" | true |
false, "false", "0", "off", "no", "" | false |
| Any other non-empty string | true |
$caster->cast('bool', 'yes'); // true
$caster->cast('bool', 'no'); // false
$caster->cast('bool', '1'); // true
$caster->cast('bool', ''); // falseString
$caster->cast('string', 123); // "123"
$caster->cast('string', ['a' => 1]); // '{"a":1}'Array
Smart conversion logic:
- JSON: Valid JSON array/object is decoded
- CSV: Comma-separated string is split
- Single: Non-empty string wrapped in array
- Empty: Empty string becomes
[]
$caster->cast('array', '["a","b"]'); // ["a", "b"]
$caster->cast('array', 'a, b, c'); // ["a", "b", "c"]
$caster->cast('array', 'single'); // ["single"]
$caster->cast('array', ''); // []DateTime Casting
Basic DateTime
#[Cast('datetime')]
public DateTime $createdAt;
// Accepts: ISO strings, timestamps, DateTime objects
// "2024-01-15" → DateTime
// 1705276800 → DateTimeDateTime with Format
#[Cast('datetime:Y-m-d')]
public DateTime $birthDate;
#[Cast('datetime:Y-m-d H:i:s')]
public DateTime $eventTime;DateTimeImmutable
#[Cast('datetime:immutable')]
public DateTimeImmutable $timestamp;
#[Cast('datetime:immutable:Y-m-d')]
public DateTimeImmutable $date;Custom Casters (#[Caster])
Implement CasterInterface for complex types and plug them in via #[Caster]:
use Solo\RequestHandler\Attributes\Caster;
use Solo\RequestHandler\Contracts\CasterInterface;
final class MoneyCaster implements CasterInterface
{
public function cast(mixed $value): Money
{
return new Money((int) round((float) $value * 100));
}
}Usage:
#[Caster(MoneyCaster::class)]
public Money $price;#[Cast] and #[Caster] are mutually exclusive — declaring both on the same property throws ConfigurationException.
Caster with Dependencies
Register caster instance for dependency injection:
final class CurrencyCaster implements CasterInterface
{
public function __construct(
private readonly CurrencyConverter $converter
) {}
public function cast(mixed $value): Money
{
return $this->converter->convert($value);
}
}
// Register
$handler->register(CurrencyCaster::class, new CurrencyCaster($converter));PostProcessor Skips Auto-Cast
When #[PostProcess] is defined, automatic casting is skipped (the processor is responsible for the final value):
#[PostProcess(JsonDecoder::class)]
public array $tags;
final class JsonDecoder implements ProcessorInterface
{
public function process(mixed $value, ProcessContext $context): array
{
return json_decode($value, true) ?? [];
}
}Null and Empty String Handling
null returns null for all built-in casters:
$caster->cast('int', null); // null
$caster->cast('string', null); // null
$caster->cast('array', null); // nullEmpty string "" is handled per type:
| Type | "" Result | Reason |
|---|---|---|
int, float | null | Not a valid number |
datetime | null | Not a valid date |
string | "" | Preserved as-is |
bool | false | Treated as falsy |
array | [] | Empty collection |
$caster->cast('int', ''); // null
$caster->cast('string', ''); // ""
$caster->cast('bool', ''); // false
$caster->cast('array', ''); // []Type Safety
Configuration is validated at build time:
// ❌ Error: cast type incompatible with property type
#[Cast('string')]
public int $id;
// ✅ Valid: types match
#[Cast('int')]
public int $id;
// ✅ Valid: float is compatible with int|float
#[Cast('float')]
public int|float $price;