Skip to content

Commit c6f02b6

Browse files
committed
added support for intersection types foo&bar
1 parent e31ad9e commit c6f02b6

File tree

9 files changed

+74
-15
lines changed

9 files changed

+74
-15
lines changed

readme.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,14 @@ $class->addMember($methodRecount);
188188
Types
189189
-----
190190

191-
Each type or union type can be passed as a string, you can also use predefined constants for native types:
191+
Each type or union/intersection type can be passed as a string, you can also use predefined constants for native types:
192192

193193
```php
194194
use Nette\PhpGenerator\Type;
195195

196-
$member->setType('array');
197-
$member->setType(Type::ARRAY);
198-
$member->setType('array|string');
196+
$member->setType('array'); // or Type::ARRAY;
197+
$member->setType('array|string'); // or Type::union('array', 'string')
198+
$member->setType('Foo&Bar'); // or Type::intersection(Foo::class, Bar::class)
199199
$member->setType(null); // removes type
200200
```
201201

src/PhpGenerator/Factory.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ public function fromMethodReflection(\ReflectionMethod $from): Method
126126
if ($from->getReturnType() instanceof \ReflectionNamedType) {
127127
$method->setReturnType($from->getReturnType()->getName());
128128
$method->setReturnNullable($from->getReturnType()->allowsNull());
129-
} elseif ($from->getReturnType() instanceof \ReflectionUnionType) {
129+
} elseif (
130+
$from->getReturnType() instanceof \ReflectionUnionType
131+
|| $from->getReturnType() instanceof \ReflectionIntersectionType
132+
) {
130133
$method->setReturnType((string) $from->getReturnType());
131134
}
132135
return $method;
@@ -147,7 +150,10 @@ public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody
147150
if ($from->getReturnType() instanceof \ReflectionNamedType) {
148151
$function->setReturnType($from->getReturnType()->getName());
149152
$function->setReturnNullable($from->getReturnType()->allowsNull());
150-
} elseif ($from->getReturnType() instanceof \ReflectionUnionType) {
153+
} elseif (
154+
$from->getReturnType() instanceof \ReflectionUnionType
155+
|| $from->getReturnType() instanceof \ReflectionIntersectionType
156+
) {
151157
$function->setReturnType((string) $from->getReturnType());
152158
}
153159
$function->setBody($withBody ? $this->loadFunctionBody($from) : '');
@@ -174,7 +180,10 @@ public function fromParameterReflection(\ReflectionParameter $from): Parameter
174180
if ($from->getType() instanceof \ReflectionNamedType) {
175181
$param->setType($from->getType()->getName());
176182
$param->setNullable($from->getType()->allowsNull());
177-
} elseif ($from->getType() instanceof \ReflectionUnionType) {
183+
} elseif (
184+
$from->getType() instanceof \ReflectionUnionType
185+
|| $from->getType() instanceof \ReflectionIntersectionType
186+
) {
178187
$param->setType((string) $from->getType());
179188
}
180189
if ($from->isDefaultValueAvailable()) {
@@ -228,7 +237,10 @@ public function fromPropertyReflection(\ReflectionProperty $from): Property
228237
if ($from->getType() instanceof \ReflectionNamedType) {
229238
$prop->setType($from->getType()->getName());
230239
$prop->setNullable($from->getType()->allowsNull());
231-
} elseif ($from->getType() instanceof \ReflectionUnionType) {
240+
} elseif (
241+
$from->getType() instanceof \ReflectionUnionType
242+
|| $from->getType() instanceof \ReflectionIntersectionType
243+
) {
232244
$prop->setType((string) $from->getType());
233245
}
234246
$prop->setInitialized($from->hasType() && array_key_exists($prop->getName(), $defaults));

src/PhpGenerator/PhpNamespace.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@ public function getUses(): array
126126
}
127127

128128

129-
public function unresolveUnionType(string $type): string
129+
public function unresolveType(string $type): string
130130
{
131-
return implode('|', array_map([$this, 'unresolveName'], explode('|', $type)));
131+
return preg_replace_callback('~[^|&?]+~', function ($m) { return $this->unresolveName($m[0]); }, $type);
132132
}
133133

134134

src/PhpGenerator/Printer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public function printClass(ClassType $class, PhpNamespace $namespace = null): st
119119
{
120120
$class->validate();
121121
$resolver = $this->resolveTypes && $namespace
122-
? [$namespace, 'unresolveUnionType']
122+
? [$namespace, 'unresolveType']
123123
: function ($s) { return $s; };
124124

125125
$traits = [];
@@ -310,7 +310,7 @@ public function printType(?string $type, bool $nullable = false, PhpNamespace $n
310310
return '';
311311
}
312312
if ($this->resolveTypes && $namespace) {
313-
$type = $namespace->unresolveUnionType($type);
313+
$type = $namespace->unresolveType($type);
314314
}
315315
if ($nullable && strcasecmp($type, 'mixed')) {
316316
$type = strpos($type, '|') === false

src/PhpGenerator/Type.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ public static function union(string ...$types): string
4646
}
4747

4848

49+
public static function intersection(string ...$types): string
50+
{
51+
return implode('&', $types);
52+
}
53+
54+
4955
public static function getType($value): ?string
5056
{
5157
if (is_object($value)) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
/**
4+
* @phpVersion 8.1
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Nette\PhpGenerator\ClassType;
10+
11+
12+
require __DIR__ . '/../bootstrap.php';
13+
require __DIR__ . '/fixtures/classes.php81';
14+
15+
$res[] = ClassType::from(new Abc\Class11);
16+
17+
sameFile(__DIR__ . '/expected/ClassType.from.81.expect', implode("\n", $res));

tests/PhpGenerator/PhpNamespace.phpt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ Assert::same('\A', $namespace->unresolveName('\A'));
3636
Assert::same('\A', $namespace->unresolveName('A'));
3737
Assert::same('A', $namespace->unresolveName('foo\A'));
3838

39-
Assert::same('A', $namespace->unresolveUnionType('foo\A'));
40-
Assert::same('null|A', $namespace->unresolveUnionType('null|foo\A'));
41-
Assert::same('', $namespace->unresolveUnionType(''));
39+
Assert::same('A', $namespace->unresolveType('foo\A'));
40+
Assert::same('null|A', $namespace->unresolveType('null|foo\A'));
41+
Assert::same('?A', $namespace->unresolveType('?foo\A'));
42+
Assert::same('A&\Countable', $namespace->unresolveType('foo\A&Countable'));
43+
Assert::same('', $namespace->unresolveType(''));
4244

4345
$namespace->addUse('Bar\C');
4446
Assert::same(['C' => 'Bar\\C'], $namespace->getUses());
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class Class11
2+
{
3+
public Foo&Bar $foo;
4+
5+
6+
public function foo(Foo&Bar $c): Foo&Bar
7+
{
8+
}
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abc;
6+
7+
class Class11
8+
{
9+
public Foo&Bar $foo;
10+
11+
public function foo(Foo&Bar $c): Foo&Bar {
12+
}
13+
}

0 commit comments

Comments
 (0)