Skip to content
This repository was archived by the owner on Sep 1, 2023. It is now read-only.

Commit f2decec

Browse files
committed
Work around is_a() not working for value-types with magic interfaces
e.g. `[] instanceof Traversable`, but ! `is_a([], Traversable::class)` fixes #20
1 parent 646fab9 commit f2decec

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

src/TypeSpec/__Private/KeyedTraversableSpec.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,24 @@ public function __construct(
2626
}
2727

2828
public function assertType(mixed $value): T {
29-
if (!is_a($value, $this->outer)) {
30-
throw
31-
IncorrectTypeException::withValue($this->getTrace(), $this->outer.'<Tk, Tv>', $value);
29+
// Switch is needed as values such as PHP arrays pass instanceof, but not is_a()
30+
switch ($this->outer) {
31+
case KeyedContainer::class:
32+
$valid_outer = $value instanceof KeyedContainer;
33+
break;
34+
case KeyedTraversable::class:
35+
$valid_outer = $value instanceof KeyedTraversable;
36+
break;
37+
default:
38+
$valid_outer = is_a($value, $this->outer);
39+
}
40+
41+
if (!$valid_outer) {
42+
throw IncorrectTypeException::withValue(
43+
$this->getTrace(),
44+
$this->outer.'<Tk, Tv>',
45+
$value,
46+
);
3247
}
3348

3449
invariant(

src/TypeSpec/__Private/TraversableSpec.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,19 @@ public function __construct(
3131
public function assertType(mixed $value): T {
3232
$frame = $this->outer.'<T>';
3333

34-
if (!is_a($value, $this->outer)) {
34+
// Switch is needed as values such as PHP arrays pass instanceof, but not is_a()
35+
switch ($this->outer) {
36+
case Container::class:
37+
$valid_outer = $value instanceof Container;
38+
break;
39+
case Traversable::class:
40+
$valid_outer = $value instanceof Traversable;
41+
break;
42+
default:
43+
$valid_outer = is_a($value, $this->outer);
44+
}
45+
46+
if (!$valid_outer) {
3547
throw
3648
IncorrectTypeException::withValue($this->getTrace(), $frame, $value);
3749
}

tests/TypeStructureTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ public function getExampleValidTypes(): array<string, (mixed, mixed)> {
5555
),
5656
'Traversable<int>' =>
5757
tuple(type_structure(C::class, 'TIntTraversable'), Vector { 123, 456 }),
58+
'array as Container<int>' =>
59+
tuple(type_structure(C::class, 'TIntContainer'), [123, 456]),
5860
'Container<int>' =>
5961
tuple(type_structure(C::class, 'TIntContainer'), Vector { 123, 456 }),
6062
'KeyedTraversable<string, int>' => tuple(
@@ -65,6 +67,10 @@ public function getExampleValidTypes(): array<string, (mixed, mixed)> {
6567
type_structure(C::class, 'TStringIntKeyedContainer'),
6668
Map { 'foo' => 123 },
6769
),
70+
'PHP array as KeyedContainer<string, int>' => tuple(
71+
type_structure(C::class, 'TStringIntKeyedContainer'),
72+
['foo' => 123],
73+
),
6874
'empty Map<string, string>' =>
6975
tuple(type_structure(C::class, 'TStringStringMap'), Map {}),
7076
'Map<string, string>' => tuple(

0 commit comments

Comments
 (0)