Type-safe, exception-free casting utility for PHP 8.5+ applications.
Modern PHP development with strict types (declare(strict_types=1)) demands precise type handling. However, many data sources in PHP return mixed or loosely-typed values:
- Superglobals (
$_GET,$_POST,$_SERVER,$_ENV,$_COOKIE,$_SESSION) returnmixed - Environment variables via
getenv()returnstring|false - Legacy libraries often return untyped or loosely-typed data
- Database results may return strings for numeric columns
- Configuration files (JSON, XML, YAML, INI) parse to mixed arrays
- External APIs return decoded JSON with uncertain types
PHP's native type casting ((int), (string), etc.) is permissive and can silently produce unexpected results:
(int) "42abc"; // 42 (silently ignores "abc")
(int) []; // 0 (arrays become 0 or 1)
(bool) "false"; // true (non-empty string)
(float) "invalid"; // 0.0 (no error)This library provides predictable, exception-free type conversions. When a value cannot be cast, a safe default is returned instead of throwing an exception, making it ideal for use in hot paths, middleware, and defensive code where unexpected input must never interrupt execution.
When a value cannot be cast to the target type, the following defaults are returned:
| Method | Default Return |
|---|---|
toArray |
[] |
toBool |
false |
toFloat |
0.0 |
toInt |
0 |
toJson |
'{}' |
toString |
'' |
- Silent data corruption: Native casts convert invalid values in unpredictable ways; this library uses clear, documented rules
- Inconsistent boolean handling: PHP treats
"false","no","off"astrue; this library treats them asfalse - Missing validation: No built-in way to reject non-numeric strings for number conversion
- Overflow handling: Native
(int)silently wraps on overflow; this library returns0 - Type ambiguity: Superglobals and legacy code return
mixed, breaking strict typing
When working with $_GET, $_POST, $_SERVER, $_ENV, and other superglobals, values are always mixed. This library ensures type-safe access:
use Ctw\Cast\Cast;
// Environment variables
$debug = Cast::toBool($_ENV['DEBUG'] ?? 'false');
$port = Cast::toInt($_ENV['DB_PORT'] ?? '3306');
$timeout = Cast::toFloat($_ENV['TIMEOUT'] ?? '30.0');
$appName = Cast::toString($_ENV['APP_NAME'] ?? '');
// GET/POST parameters
$page = Cast::toInt($_GET['page'] ?? '1');
$limit = Cast::toInt($_GET['limit'] ?? '10');
$active = Cast::toBool($_POST['active'] ?? 'false');
$tags = Cast::toArray($_POST['tags'] ?? '[]');
// Server variables
$port = Cast::toInt($_SERVER['SERVER_PORT'] ?? '80');
$https = Cast::toBool($_SERVER['HTTPS'] ?? 'off');
// Session data
$userId = Cast::toInt($_SESSION['user_id'] ?? '0');
$prefs = Cast::toArray($_SESSION['preferences'] ?? '{}');Many older PHP libraries return untyped data. This library bridges the gap between legacy code and modern strict-typed applications:
use Ctw\Cast\Cast;
// Legacy database result (returns strings for all columns)
$row = $legacyDb->fetchRow("SELECT id, price, active FROM products");
$id = Cast::toInt($row['id']);
$price = Cast::toFloat($row['price']);
$active = Cast::toBool($row['active']);
// Legacy configuration loader
$config = $legacyLoader->load('app.ini');
$maxSize = Cast::toInt($config['upload_max_size']);
$debugMode = Cast::toBool($config['debug']);
$allowedIps = Cast::toArray($config['allowed_ips']);
// Legacy API client
$response = $legacyClient->get('/api/users');
$users = Cast::toArray($response);
$jsonOut = Cast::toJson($users);
// Untyped function returns
$result = some_legacy_function();
$count = Cast::toInt($result);- Controllers: Cast request parameters to expected types
- Service layers: Ensure type safety when processing external data
- CLI commands: Parse command-line arguments and environment variables
- Data mappers: Convert database results to typed domain objects
- API handlers: Decode incoming JSON payloads
- Configuration loaders: Parse config values
- Queue workers: Process messages with mixed payloads
- Middleware: Normalize request/response data
- Never throw: Every method returns a safe default when a value cannot be cast
- Explicit behavior: Every conversion rule is documented and predictable
- No silent corruption: Ambiguous values produce the documented default, not a guess
- PHPStan/Psalm friendly: Return types are precise, enabling static analysis
- Zero dependencies: No external packages required
- PHP 8.5 or higher
- strict_types enabled
Install by adding the package as a Composer requirement:
composer require ctw/ctw-castuse Ctw\Cast\Cast;
$string = Cast::toString($value);
$int = Cast::toInt($value);
$float = Cast::toFloat($value);
$bool = Cast::toBool($value);
$array = Cast::toArray($value);
$json = Cast::toJson($value);Converts values to string representation with explicit, predictable rules. Returns '' for values that cannot be cast.
Cast::toString(42); // "42"
Cast::toString(true); // "1"
Cast::toString(null); // ""
Cast::toString([1, 2, 3]); // ""| Input Type | Input Value | Output |
|---|---|---|
| string | "hello" |
"hello" |
| int | 42 |
"42" |
| int | -17 |
"-17" |
| int | 0 |
"0" |
| float | 3.14 |
"3.14" |
| float | -2.5 |
"-2.5" |
| float | 1.0 |
"1" |
| float | INF |
"INF" |
| float | NAN |
"NAN" |
| bool | true |
"1" |
| bool | false |
"0" |
| null | null |
"" |
| object | with __toString() |
__toString() result |
| object | without __toString() |
"" |
| array | [1, 2, 3] |
"" |
| resource | fopen(...) |
"" |
Converts values to integers with rounding for floats. Returns 0 for values that cannot be cast.
Cast::toInt("42"); // 42
Cast::toInt(3.7); // 4 (rounded)
Cast::toInt(null); // 0
Cast::toInt("hello"); // 0
Cast::toInt(INF); // 0| Input Type | Input Value | Output |
|---|---|---|
| int | 42 |
42 |
| int | -17 |
-17 |
| bool | true |
1 |
| bool | false |
0 |
| null | null |
0 |
| float | 3.14 |
3 (rounded) |
| float | 3.5 |
4 (rounded) |
| float | -2.7 |
-3 (rounded) |
| string | "42" |
42 |
| string | " 42 " |
42 (trimmed) |
| string | "3.14" |
3 (rounded) |
| string | "1e3" |
1000 |
| float | INF |
0 |
| float | NAN |
0 |
| float | 1e20 (overflow) |
0 |
| string | "" |
0 |
| string | "hello" |
0 |
| string | "42abc" |
0 |
| string | out of int range | 0 |
| array | [1, 2, 3] |
0 |
| object | stdClass |
0 |
| resource | fopen(...) |
0 |
Converts values to floating-point numbers. Returns 0.0 for values that cannot be cast.
Cast::toFloat("3.14"); // 3.14
Cast::toFloat(42); // 42.0
Cast::toFloat(true); // 1.0
Cast::toFloat("hello"); // 0.0| Input Type | Input Value | Output |
|---|---|---|
| float | 3.14 |
3.14 |
| float | -2.5 |
-2.5 |
| float | INF |
INF |
| float | NAN |
NAN |
| int | 42 |
42.0 |
| int | -17 |
-17.0 |
| int | 0 |
0.0 |
| bool | true |
1.0 |
| bool | false |
0.0 |
| null | null |
0.0 |
| string | "3.14" |
3.14 |
| string | " 3.14 " |
3.14 (trimmed) |
| string | "42" |
42.0 |
| string | "1e3" |
1000.0 |
| string | "-2.5" |
-2.5 |
| string | "" |
0.0 |
| string | "hello" |
0.0 |
| string | "42abc" |
0.0 |
| array | [1, 2, 3] |
0.0 |
| object | stdClass |
0.0 |
| resource | fopen(...) |
0.0 |
Strict boolean conversion with explicit allowed values. Returns false for values that cannot be interpreted unambiguously.
Cast::toBool("yes"); // true
Cast::toBool(0); // false
Cast::toBool(null); // false
Cast::toBool("maybe"); // false
Cast::toBool(42); // false| Input Type | Input Value | Output |
|---|---|---|
| bool | true |
true |
| bool | false |
false |
| int | 1 |
true |
| int | 0 |
false |
| float | 1.0 |
true |
| float | 0.0 |
false |
| null | null |
false |
| string | "true" |
true |
| string | "1" |
true |
| string | "yes" |
true |
| string | "on" |
true |
| string | "y" |
true |
| string | "t" |
true |
| string | "false" |
false |
| string | "0" |
false |
| string | "no" |
false |
| string | "off" |
false |
| string | "n" |
false |
| string | "f" |
false |
| string | "" |
false |
| string | " TRUE " |
true (trimmed, case-insensitive) |
| int | 2 |
false |
| int | -1 |
false |
| float | 3.14 |
false |
| float | -1.0 |
false |
| string | "hello" |
false |
| string | "2" |
false |
| array | [1, 2, 3] |
false |
| object | stdClass |
false |
| resource | fopen(...) |
false |
Intelligent array conversion with multiple strategies for different types. Returns [] for values that cannot be cast.
Cast::toArray('{"a":1}'); // ["a" => 1]
Cast::toArray(42); // [42]
Cast::toArray(null); // []| Input Type | Input Value | Output |
|---|---|---|
| array | [1, 2, 3] |
[1, 2, 3] |
| null | null |
[] |
| string | "" |
[] |
| string | " " |
[] (trimmed) |
| string | '{"a":1}' |
["a" => 1] (JSON parsed) |
| string | '[1,2,3]' |
[1, 2, 3] (JSON parsed) |
| string | '{invalid}' |
['{invalid}'] (wrapped) |
| string | "hello" |
["hello"] (wrapped) |
| int | 42 |
[42] |
| float | 3.14 |
[3.14] |
| bool | true |
[true] |
| object | Traversable |
iterator_to_array() result |
| object | with toArray() |
toArray() result |
| object | stdClass{a:1} |
["a" => 1] (via get_object_vars) |
| resource | fopen(...) |
[] |
Type-safe JSON encoding. Returns '{}' when encoding fails (INF/NAN, invalid UTF-8, depth exceeded, resources, etc.).
Cast::toJson(['name' => 'John']); // '{"name":"John"}'
Cast::toJson(true); // 'true'
Cast::toJson(null); // 'null'
Cast::toJson(INF); // '{}'| Input Type | Input Value | Output |
|---|---|---|
| null | null |
"null" |
| string | "hello" |
"\"hello\"" |
| string | "with/slash" |
"\"with/slash\"" |
| int | 42 |
"42" |
| int | -17 |
"-17" |
| bool | true |
"true" |
| bool | false |
"false" |
| float | 3.14 |
"3.14" |
| array | [1, 2, 3] |
"[1,2,3]" |
| array | ["a" => 1] |
"{\"a\":1}" |
| object | JsonSerializable |
via jsonSerialize() |
| object | with toArray() |
via toArray() |
| object | stdClass{a:1} |
"{\"a\":1}" |
| float | INF |
"{}" |
| float | NAN |
"{}" |
| (any) | depth < 1 | "{}" |
| object | toArray() not returning array |
"{}" |
| resource | fopen(...) |
"{}" |
Default flags: JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
This library never throws exceptions. When a value cannot be cast to the target type, a documented default value is returned instead:
use Ctw\Cast\Cast;
$int = Cast::toInt($userInput); // 0 if not castable
$str = Cast::toString($userInput); // '' if not castable
$bool = Cast::toBool($userInput); // false if not castable
$float = Cast::toFloat($userInput); // 0.0 if not castable
$arr = Cast::toArray($userInput); // [] if not castable
$json = Cast::toJson($userInput); // '{}' if not castableBecause no exceptions are thrown, there is no need for try/catch blocks around cast calls.