1--TEST-- 2Union types in reflection 3--FILE-- 4<?php 5 6function dumpType(ReflectionUnionType $rt) { 7 echo "Type $rt:\n"; 8 echo "Allows null: " . ($rt->allowsNull() ? "true" : "false") . "\n"; 9 foreach ($rt->getTypes() as $type) { 10 echo " Name: " . $type->getName() . "\n"; 11 echo " String: " . (string) $type . "\n"; 12 echo " Allows Null: " . ($type->allowsNull() ? "true" : "false") . "\n"; 13 } 14} 15 16function dumpBCType(ReflectionNamedType $rt) { 17 echo "Type $rt:\n"; 18 echo " Name: " . $rt->getName() . "\n"; 19 echo " String: " . (string) $rt . "\n"; 20 echo " Allows Null: " . ($rt->allowsNull() ? "true" : "false") . "\n"; 21} 22 23function test1(): X|Y|int|float|false|null { } 24function test2(): X|iterable|bool { } 25function test3(): null|false { } 26function test4(): ?false { } 27function test5(): X|iterable|true { } 28function test6(): null|true { } 29function test7(): ?true { } 30 31class Test { 32 public X|Y|int $prop; 33} 34 35dumpType((new ReflectionFunction('test1'))->getReturnType()); 36dumpType((new ReflectionFunction('test2'))->getReturnType()); 37dumpBCType((new ReflectionFunction('test3'))->getReturnType()); 38dumpBCType((new ReflectionFunction('test4'))->getReturnType()); 39dumpType((new ReflectionFunction('test5'))->getReturnType()); 40dumpBCType((new ReflectionFunction('test6'))->getReturnType()); 41dumpBCType((new ReflectionFunction('test7'))->getReturnType()); 42 43$rc = new ReflectionClass(Test::class); 44$rp = $rc->getProperty('prop'); 45dumpType($rp->getType()); 46 47/* Force CE resolution of the property type */ 48 49class x {} 50$test = new Test; 51$test->prop = new x; 52 53$rp = $rc->getProperty('prop'); 54dumpType($rp->getType()); 55 56class y {} 57$test->prop = new y; 58 59$rp = $rc->getProperty('prop'); 60dumpType($rp->getType()); 61 62?> 63--EXPECT-- 64Type X|Y|int|float|false|null: 65Allows null: true 66 Name: X 67 String: X 68 Allows Null: false 69 Name: Y 70 String: Y 71 Allows Null: false 72 Name: int 73 String: int 74 Allows Null: false 75 Name: float 76 String: float 77 Allows Null: false 78 Name: false 79 String: false 80 Allows Null: false 81 Name: null 82 String: null 83 Allows Null: true 84Type X|Traversable|array|bool: 85Allows null: false 86 Name: X 87 String: X 88 Allows Null: false 89 Name: Traversable 90 String: Traversable 91 Allows Null: false 92 Name: array 93 String: array 94 Allows Null: false 95 Name: bool 96 String: bool 97 Allows Null: false 98Type ?false: 99 Name: false 100 String: ?false 101 Allows Null: true 102Type ?false: 103 Name: false 104 String: ?false 105 Allows Null: true 106Type X|Traversable|array|true: 107Allows null: false 108 Name: X 109 String: X 110 Allows Null: false 111 Name: Traversable 112 String: Traversable 113 Allows Null: false 114 Name: array 115 String: array 116 Allows Null: false 117 Name: true 118 String: true 119 Allows Null: false 120Type ?true: 121 Name: true 122 String: ?true 123 Allows Null: true 124Type ?true: 125 Name: true 126 String: ?true 127 Allows Null: true 128Type X|Y|int: 129Allows null: false 130 Name: X 131 String: X 132 Allows Null: false 133 Name: Y 134 String: Y 135 Allows Null: false 136 Name: int 137 String: int 138 Allows Null: false 139Type X|Y|int: 140Allows null: false 141 Name: X 142 String: X 143 Allows Null: false 144 Name: Y 145 String: Y 146 Allows Null: false 147 Name: int 148 String: int 149 Allows Null: false 150Type X|Y|int: 151Allows null: false 152 Name: X 153 String: X 154 Allows Null: false 155 Name: Y 156 String: Y 157 Allows Null: false 158 Name: int 159 String: int 160 Allows Null: false 161