Skip to content

Commit cced8a2

Browse files
committed
Optimize type coercion logic
1 parent 36826f8 commit cced8a2

File tree

88 files changed

+535
-284
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+535
-284
lines changed

.php-cs-fixer.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,21 +178,41 @@
178178
'property-read',
179179
'property-write',
180180
],
181-
['internal', 'psalm-internal', 'phpstan-internal'],
181+
[
182+
'internal',
183+
'psalm-internal',
184+
'phpstan-internal',
185+
],
182186
[
183187
'template',
184188
'template-covariant',
189+
],
190+
[
185191
'template-extends',
186192
'extends',
187193
'template-implements',
188194
'implements',
195+
],
196+
[
189197
'psalm-require-implements',
190198
'phpstan-require-implements',
199+
'require-implements',
191200
'psalm-require-extends',
192201
'phpstan-require-extends',
202+
'require-extends',
203+
],
204+
[
205+
'psalm-taint-sink',
206+
'param',
207+
'phpstan-param',
208+
'psalm-param',
209+
],
210+
[
211+
'phpstan-return',
212+
'psalm-return',
213+
'return',
214+
'throws'
193215
],
194-
['psalm-taint-sink', 'param'],
195-
['return', 'throws'],
196216
['psalm-suppress'],
197217
],
198218
],

example/03.types/02.custom-type.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@
77
use TypeLang\Mapper\Mapper;
88
use TypeLang\Mapper\Platform\StandardPlatform;
99
use TypeLang\Mapper\Type\Builder\SimpleTypeBuilder;
10+
use TypeLang\Mapper\Type\MatchedResult;
1011
use TypeLang\Mapper\Type\TypeInterface;
1112

1213
require __DIR__ . '/../../vendor/autoload.php';
1314

1415
// Add new type (must implement TypeInterface)
1516
class MyNonEmptyStringType implements TypeInterface
1617
{
17-
public function match(mixed $value, RuntimeContext $context): bool
18+
public function match(mixed $value, RuntimeContext $context): ?MatchedResult
1819
{
19-
return \is_string($value) && $value !== '';
20+
return MatchedResult::successIf($value, \is_string($value) && $value !== '');
2021
}
2122

2223
public function cast(mixed $value, RuntimeContext $context): string

example/03.types/03.custom-type-template-arguments.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use TypeLang\Mapper\Mapper;
99
use TypeLang\Mapper\Platform\StandardPlatform;
1010
use TypeLang\Mapper\Type\Builder\Builder;
11+
use TypeLang\Mapper\Type\MatchedResult;
1112
use TypeLang\Mapper\Type\TypeInterface;
1213
use TypeLang\Parser\Node\Stmt\NamedTypeNode;
1314
use TypeLang\Parser\Node\Stmt\TypeStatement;
@@ -47,9 +48,9 @@ public function __construct(
4748
private readonly TypeInterface $type,
4849
) {}
4950

50-
public function match(mixed $value, RuntimeContext $context): bool
51+
public function match(mixed $value, RuntimeContext $context): ?MatchedResult
5152
{
52-
return !empty($value);
53+
return MatchedResult::successIf($value, !empty($value));
5354
}
5455

5556
public function cast(mixed $value, RuntimeContext $context): mixed

example/03.types/05.custom-type-callable.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use TypeLang\Mapper\Platform\DelegatePlatform;
1010
use TypeLang\Mapper\Platform\StandardPlatform;
1111
use TypeLang\Mapper\Type\Builder\CallableTypeBuilder;
12+
use TypeLang\Mapper\Type\MatchedResult;
1213
use TypeLang\Mapper\Type\TypeInterface;
1314

1415
require __DIR__ . '/../../vendor/autoload.php';
@@ -45,9 +46,9 @@ public function has(string $id): bool
4546
// Add new type (must implement TypeInterface)
4647
class MyNonEmptyStringType implements TypeInterface
4748
{
48-
public function match(mixed $value, RuntimeContext $context): bool
49+
public function match(mixed $value, RuntimeContext $context): ?MatchedResult
4950
{
50-
return \is_string($value) && $value !== '';
51+
return MatchedResult::successIf($value, \is_string($value) && $value !== '');
5152
}
5253

5354
public function cast(mixed $value, RuntimeContext $context): string
@@ -56,7 +57,6 @@ public function cast(mixed $value, RuntimeContext $context): string
5657
return $value;
5758
}
5859

59-
6060
throw new InvalidValueException(
6161
value: $value,
6262
path: $context->getPath(),

example/03.types/06.custom-type-psr-container.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use TypeLang\Mapper\Platform\DelegatePlatform;
1010
use TypeLang\Mapper\Platform\StandardPlatform;
1111
use TypeLang\Mapper\Type\Builder\PsrContainerTypeBuilder;
12+
use TypeLang\Mapper\Type\MatchedResult;
1213
use TypeLang\Mapper\Type\TypeInterface;
1314

1415
require __DIR__ . '/../../vendor/autoload.php';
@@ -43,9 +44,9 @@ public function has(string $id): bool
4344
// Add new type (must implement TypeInterface)
4445
class MyNonEmptyStringType implements TypeInterface
4546
{
46-
public function match(mixed $value, RuntimeContext $context): bool
47+
public function match(mixed $value, RuntimeContext $context): ?MatchedResult
4748
{
48-
return \is_string($value) && $value !== '';
49+
return MatchedResult::successIf($value, \is_string($value) && $value !== '');
4950
}
5051

5152
public function cast(mixed $value, RuntimeContext $context): string

src/Coercer/ArrayKeyTypeCoercer.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
namespace TypeLang\Mapper\Coercer;
66

77
use TypeLang\Mapper\Context\RuntimeContext;
8-
use TypeLang\Mapper\Exception\Runtime\InvalidValueException;
98

109
/**
1110
* @template-implements TypeCoercerInterface<array-key>
1211
*/
1312
class ArrayKeyTypeCoercer implements TypeCoercerInterface
1413
{
15-
public function coerce(mixed $value, RuntimeContext $context): int|string
14+
public function tryCoerce(mixed $value, RuntimeContext $context): mixed
1615
{
1716
return match (true) {
1817
\is_string($value),
@@ -26,7 +25,7 @@ public function coerce(mixed $value, RuntimeContext $context): int|string
2625
// Enum
2726
$value instanceof \BackedEnum => $value->value,
2827
$value instanceof \UnitEnum => $value->name,
29-
default => throw InvalidValueException::createFromContext($context),
28+
default => $value,
3029
};
3130
}
3231
}

src/Coercer/ArrayTypeCoercer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
namespace TypeLang\Mapper\Coercer;
66

77
use TypeLang\Mapper\Context\RuntimeContext;
8-
use TypeLang\Mapper\Exception\Runtime\InvalidValueException;
98

109
/**
1110
* @template-implements TypeCoercerInterface<array<array-key, mixed>>
1211
*/
1312
class ArrayTypeCoercer implements TypeCoercerInterface
1413
{
15-
public function coerce(mixed $value, RuntimeContext $context): array
14+
public function tryCoerce(mixed $value, RuntimeContext $context): mixed
1615
{
1716
return match (true) {
1817
\is_array($value) => $value,
1918
$value instanceof \Traversable => \iterator_to_array($value, true),
20-
default => throw InvalidValueException::createFromContext($context),
19+
\is_object($value) => (array) $value,
20+
default => $value,
2121
};
2222
}
2323
}

src/Coercer/BoolTypeCoercer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212
class BoolTypeCoercer implements TypeCoercerInterface
1313
{
14-
public function coerce(mixed $value, RuntimeContext $context): bool
14+
public function tryCoerce(mixed $value, RuntimeContext $context): mixed
1515
{
1616
//
1717
// Each value should be checked EXPLICITLY, instead

src/Coercer/FloatTypeCoercer.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
namespace TypeLang\Mapper\Coercer;
66

77
use TypeLang\Mapper\Context\RuntimeContext;
8-
use TypeLang\Mapper\Exception\Runtime\InvalidValueException;
98

109
/**
1110
* @template-implements TypeCoercerInterface<float>
1211
*/
1312
class FloatTypeCoercer implements TypeCoercerInterface
1413
{
15-
public function coerce(mixed $value, RuntimeContext $context): float
14+
public function tryCoerce(mixed $value, RuntimeContext $context): mixed
1615
{
1716
if ($value instanceof \BackedEnum && \is_int($value->value)) {
1817
return (float) $value->value;
@@ -25,7 +24,7 @@ public function coerce(mixed $value, RuntimeContext $context): float
2524
$value === false,
2625
$value === null => 0.0,
2726
$value === true => 1.0,
28-
default => throw InvalidValueException::createFromContext($context),
27+
default => null,
2928
};
3029
}
3130
}

src/Coercer/IntTypeCoercer.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
namespace TypeLang\Mapper\Coercer;
66

77
use TypeLang\Mapper\Context\RuntimeContext;
8-
use TypeLang\Mapper\Exception\Runtime\InvalidValueException;
98

109
/**
1110
* @template-implements TypeCoercerInterface<int>
1211
*/
1312
class IntTypeCoercer implements TypeCoercerInterface
1413
{
15-
public function coerce(mixed $value, RuntimeContext $context): int
14+
public function tryCoerce(mixed $value, RuntimeContext $context): mixed
1615
{
1716
if ($value instanceof \BackedEnum && \is_int($value->value)) {
1817
return $value->value;
@@ -30,7 +29,7 @@ public function coerce(mixed $value, RuntimeContext $context): int
3029
$value === true => 1,
3130
// Resource to int type coercion is not obvious:
3231
// \is_resource($value) => \get_resource_id($value),
33-
default => throw InvalidValueException::createFromContext($context),
32+
default => $value,
3433
};
3534
}
3635

0 commit comments

Comments
 (0)