1--TEST--
2Disjunctive Normal Form types in reflection
3--FILE--
4<?php
5
6function dumpType(ReflectionType $rt, int $indent = 0) {
7    $str_indent = str_repeat(' ', 2 * $indent);
8    echo $str_indent . "Type $rt is " . $rt::class . ":\n";
9    foreach ($rt->getTypes() as $type) {
10        if ($type instanceof ReflectionNamedType) {
11            echo $str_indent . "  Name: " . $type->getName() . "\n";
12            echo $str_indent . "  String: " . (string) $type . "\n";
13            echo $str_indent . "  Allows Null: " . json_encode($type->allowsNull()) . "\n";
14        } else {
15            dumpType($type, $indent+1);
16        }
17    }
18}
19
20function test1(): (X&Y)|(Z&Traversable)|Countable { }
21
22class Test {
23    public (X&Y)|Countable $prop;
24}
25
26dumpType((new ReflectionFunction('test1'))->getReturnType());
27
28$rc = new ReflectionClass(Test::class);
29$rp = $rc->getProperty('prop');
30dumpType($rp->getType());
31
32/* Force CE resolution of the property type */
33
34interface y {}
35class x implements Y, Countable {
36    public function count(): int { return 0; }
37}
38$test = new Test;
39$test->prop = new x;
40
41$rp = $rc->getProperty('prop');
42dumpType($rp->getType());
43
44?>
45--EXPECT--
46Type (X&Y)|(Z&Traversable)|Countable is ReflectionUnionType:
47  Type X&Y is ReflectionIntersectionType:
48    Name: X
49    String: X
50    Allows Null: false
51    Name: Y
52    String: Y
53    Allows Null: false
54  Type Z&Traversable is ReflectionIntersectionType:
55    Name: Z
56    String: Z
57    Allows Null: false
58    Name: Traversable
59    String: Traversable
60    Allows Null: false
61  Name: Countable
62  String: Countable
63  Allows Null: false
64Type (X&Y)|Countable is ReflectionUnionType:
65  Type X&Y is ReflectionIntersectionType:
66    Name: X
67    String: X
68    Allows Null: false
69    Name: Y
70    String: Y
71    Allows Null: false
72  Name: Countable
73  String: Countable
74  Allows Null: false
75Type (X&Y)|Countable is ReflectionUnionType:
76  Type X&Y is ReflectionIntersectionType:
77    Name: X
78    String: X
79    Allows Null: false
80    Name: Y
81    String: Y
82    Allows Null: false
83  Name: Countable
84  String: Countable
85  Allows Null: false
86