Skip to content

Commit 0a8a17e

Browse files
committed
added Cast [WIP]
1 parent b39bfb6 commit 0a8a17e

File tree

2 files changed

+238
-0
lines changed

2 files changed

+238
-0
lines changed

src/Utils/Cast.php

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Nette Framework (https://nette.org)
5+
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Nette\Utils;
11+
12+
use Nette;
13+
use TypeError;
14+
15+
16+
/**
17+
* Converts variables in a similar way to implicit casting in PHP in strict types mode.
18+
*/
19+
final class Cast
20+
{
21+
use Nette\StaticClass;
22+
23+
public static function bool(mixed $value): bool
24+
{
25+
return match (true) {
26+
is_bool($value) => $value,
27+
is_int($value) => $value !== 0,
28+
is_float($value) => $value !== 0.0,
29+
is_string($value) => $value !== '' && $value !== '0',
30+
default => throw new TypeError('Cannot cast ' . get_debug_type($value) . ' to bool.'),
31+
};
32+
}
33+
34+
35+
public static function int(mixed $value): int
36+
{
37+
return match (true) {
38+
is_bool($value) => (int) $value,
39+
is_int($value) => $value,
40+
is_float($value) => $value === (float) ($tmp = (int) $value)
41+
? $tmp
42+
: throw new TypeError('Cannot cast ' . self::string($value) . ' to int.'),
43+
is_string($value) => preg_match('~^-?\d+(\.0*)?$~D', $value)
44+
? (int) $value
45+
: throw new TypeError("Cannot cast '$value' to int."),
46+
default => throw new TypeError('Cannot cast ' . get_debug_type($value) . ' to int.'),
47+
};
48+
}
49+
50+
51+
public static function float(mixed $value): float
52+
{
53+
return match (true) {
54+
is_bool($value) => $value ? 1.0 : 0.0,
55+
is_int($value) => (float) $value,
56+
is_float($value) => $value,
57+
is_string($value) => preg_match('~^-?\d+(\.\d*)?$~D', $value)
58+
? (float) $value
59+
: throw new TypeError("Cannot cast '$value' to float."),
60+
default => throw new TypeError('Cannot cast ' . get_debug_type($value) . ' to float.'),
61+
};
62+
}
63+
64+
65+
public static function string(mixed $value): string
66+
{
67+
return match (true) {
68+
is_bool($value) => $value ? '1' : '0',
69+
is_int($value) => (string) $value,
70+
is_float($value) => str_contains($tmp = (string) $value, '.') ? $tmp : $tmp . '.0',
71+
is_string($value) => $value,
72+
default => throw new TypeError('Cannot cast ' . get_debug_type($value) . ' to string.'),
73+
};
74+
}
75+
76+
77+
public static function boolOrNull(mixed $value): ?bool
78+
{
79+
return $value === null ? null : self::bool($value);
80+
}
81+
82+
83+
public static function intOrNull(mixed $value): ?int
84+
{
85+
return $value === null ? null : self::int($value);
86+
}
87+
88+
89+
public static function floatOrNull(mixed $value): ?float
90+
{
91+
return $value === null ? null : self::float($value);
92+
}
93+
94+
95+
public static function stringOrNull(mixed $value): ?string
96+
{
97+
return $value === null ? null : self::string($value);
98+
}
99+
}

tests/Utils/Cast.phpt

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\Utils\Cast;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
// bool
12+
Assert::true(Cast::bool(true));
13+
Assert::true(Cast::bool(1));
14+
Assert::true(Cast::bool(2));
15+
Assert::true(Cast::bool(0.1));
16+
Assert::true(Cast::bool('1'));
17+
Assert::true(Cast::bool('0.0'));
18+
Assert::false(Cast::bool(false));
19+
Assert::false(Cast::bool(0));
20+
Assert::false(Cast::bool(0.0));
21+
Assert::false(Cast::bool(''));
22+
Assert::false(Cast::bool('0'));
23+
Assert::exception(
24+
fn() => Cast::bool([]),
25+
TypeError::class,
26+
'Cannot cast array to bool.',
27+
);
28+
Assert::exception(
29+
fn() => Cast::bool(null),
30+
TypeError::class,
31+
'Cannot cast null to bool.',
32+
);
33+
34+
35+
// int
36+
Assert::same(0, Cast::int(false));
37+
Assert::same(1, Cast::int(true));
38+
Assert::same(0, Cast::int(0));
39+
Assert::same(1, Cast::int(1));
40+
Assert::exception(
41+
fn() => Cast::int(PHP_INT_MAX + 1),
42+
TypeError::class,
43+
'Cannot cast 9.2233720368548E+18 to int.',
44+
);
45+
Assert::same(0, Cast::int(0.0));
46+
Assert::same(1, Cast::int(1.0));
47+
Assert::exception(
48+
fn() => Cast::int(0.1),
49+
TypeError::class,
50+
'Cannot cast 0.1 to int.',
51+
);
52+
Assert::exception(
53+
fn() => Cast::int(''),
54+
TypeError::class,
55+
"Cannot cast '' to int.",
56+
);
57+
Assert::same(0, Cast::int('0'));
58+
Assert::same(1, Cast::int('1'));
59+
Assert::same(-1, Cast::int('-1.'));
60+
Assert::same(1, Cast::int('1.0000'));
61+
Assert::exception(
62+
fn() => Cast::int('0.1'),
63+
TypeError::class,
64+
"Cannot cast '0.1' to int.",
65+
);
66+
Assert::exception(
67+
fn() => Cast::int([]),
68+
TypeError::class,
69+
'Cannot cast array to int.',
70+
);
71+
Assert::exception(
72+
fn() => Cast::int(null),
73+
TypeError::class,
74+
'Cannot cast null to int.',
75+
);
76+
77+
78+
// float
79+
Assert::same(0.0, Cast::float(false));
80+
Assert::same(1.0, Cast::float(true));
81+
Assert::same(0.0, Cast::float(0));
82+
Assert::same(1.0, Cast::float(1));
83+
Assert::same(0.0, Cast::float(0.0));
84+
Assert::same(1.0, Cast::float(1.0));
85+
Assert::same(0.1, Cast::float(0.1));
86+
Assert::exception(
87+
fn() => Cast::float(''),
88+
TypeError::class,
89+
"Cannot cast '' to float.",
90+
);
91+
Assert::same(0.0, Cast::float('0'));
92+
Assert::same(1.0, Cast::float('1'));
93+
Assert::same(-1.0, Cast::float('-1.'));
94+
Assert::same(1.0, Cast::float('1.0'));
95+
Assert::same(0.1, Cast::float('0.1'));
96+
Assert::exception(
97+
fn() => Cast::float([]),
98+
TypeError::class,
99+
'Cannot cast array to float.',
100+
);
101+
Assert::exception(
102+
fn() => Cast::float(null),
103+
TypeError::class,
104+
'Cannot cast null to float.',
105+
);
106+
107+
108+
// string
109+
Assert::same('0', Cast::string(false)); // differs from PHP strict casting
110+
Assert::same('1', Cast::string(true));
111+
Assert::same('0', Cast::string(0));
112+
Assert::same('1', Cast::string(1));
113+
Assert::same('0.0', Cast::string(0.0)); // differs from PHP strict casting
114+
Assert::same('1.0', Cast::string(1.0)); // differs from PHP strict casting
115+
Assert::same('-0.1', Cast::string(-0.1));
116+
Assert::same('9.2233720368548E+18', Cast::string(PHP_INT_MAX + 1));
117+
Assert::same('', Cast::string(''));
118+
Assert::same('x', Cast::string('x'));
119+
Assert::exception(
120+
fn() => Cast::string([]),
121+
TypeError::class,
122+
'Cannot cast array to string.',
123+
);
124+
Assert::exception(
125+
fn() => Cast::string(null),
126+
TypeError::class,
127+
'Cannot cast null to string.',
128+
);
129+
130+
131+
// OrNull
132+
Assert::true(Cast::boolOrNull(true));
133+
Assert::null(Cast::boolOrNull(null));
134+
Assert::same(0, Cast::intOrNull(0));
135+
Assert::null(Cast::intOrNull(null));
136+
Assert::same(0.0, Cast::floatOrNull(0));
137+
Assert::null(Cast::floatOrNull(null));
138+
Assert::same('0', Cast::stringOrNull(0));
139+
Assert::null(Cast::stringOrNull(null));

0 commit comments

Comments
 (0)