Skip to content

Commit d5c054b

Browse files
committed
Merge branch '8.x'
2 parents 128614b + f95f3af commit d5c054b

File tree

9 files changed

+134
-30
lines changed

9 files changed

+134
-30
lines changed

src/Illuminate/Events/Dispatcher.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,15 @@ public function __construct(ContainerContract $container = null)
7777
public function listen($events, $listener = null)
7878
{
7979
if ($events instanceof Closure) {
80-
return $this->listen($this->firstClosureParameterType($events), $events);
80+
return collect($this->firstClosureParameterTypes($events))
81+
->each(function ($event) use ($events) {
82+
$this->listen($event, $events);
83+
});
8184
} elseif ($events instanceof QueuedClosure) {
82-
return $this->listen($this->firstClosureParameterType($events->closure), $events->resolve());
85+
return collect($this->firstClosureParameterTypes($events->closure))
86+
->each(function ($event) use ($events) {
87+
$this->listen($event, $events->resolve());
88+
});
8389
} elseif ($listener instanceof QueuedClosure) {
8490
$listener = $listener->resolve();
8591
}

src/Illuminate/Foundation/Exceptions/Handler.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,13 @@ public function render($request, Throwable $e)
330330
$e = $this->prepareException($this->mapException($e));
331331

332332
foreach ($this->renderCallbacks as $renderCallback) {
333-
if (is_a($e, $this->firstClosureParameterType($renderCallback))) {
334-
$response = $renderCallback($e, $request);
333+
foreach ($this->firstClosureParameterTypes($renderCallback) as $type) {
334+
if (is_a($e, $type)) {
335+
$response = $renderCallback($e, $request);
335336

336-
if (! is_null($response)) {
337-
return $response;
337+
if (! is_null($response)) {
338+
return $response;
339+
}
338340
}
339341
}
340342
}

src/Illuminate/Foundation/Exceptions/ReportableHandler.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,13 @@ public function __invoke(Throwable $e)
5959
*/
6060
public function handles(Throwable $e)
6161
{
62-
return is_a($e, $this->firstClosureParameterType($this->callback));
62+
foreach ($this->firstClosureParameterTypes($this->callback) as $type) {
63+
if (is_a($e, $type)) {
64+
return true;
65+
}
66+
}
67+
68+
return false;
6369
}
6470

6571
/**

src/Illuminate/Support/Reflector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public static function getParameterClassNames($parameter)
8484
$type = $parameter->getType();
8585

8686
if (! $type instanceof ReflectionUnionType) {
87-
return [static::getParameterClassName($parameter)];
87+
return array_filter([static::getParameterClassName($parameter)]);
8888
}
8989

9090
$unionTypes = [];
@@ -97,7 +97,7 @@ public static function getParameterClassNames($parameter)
9797
$unionTypes[] = static::getTypeName($parameter, $listedType);
9898
}
9999

100-
return $unionTypes;
100+
return array_filter($unionTypes);
101101
}
102102

103103
/**

src/Illuminate/Support/Traits/ReflectsClosures.php

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,79 @@
1010
trait ReflectsClosures
1111
{
1212
/**
13-
* Get the class names / types of the parameters of the given Closure.
13+
* Get the class name of the first parameter of the given Closure.
1414
*
1515
* @param \Closure $closure
16-
* @return array
16+
* @return string
1717
*
1818
* @throws \ReflectionException
19+
* @throws \RuntimeException
1920
*/
20-
protected function closureParameterTypes(Closure $closure)
21+
protected function firstClosureParameterType(Closure $closure)
2122
{
22-
$reflection = new ReflectionFunction($closure);
23+
$types = array_values($this->closureParameterTypes($closure));
2324

24-
return collect($reflection->getParameters())->mapWithKeys(function ($parameter) {
25-
if ($parameter->isVariadic()) {
26-
return [$parameter->getName() => null];
27-
}
25+
if (! $types) {
26+
throw new RuntimeException('The given Closure has no parameters.');
27+
}
2828

29-
return [$parameter->getName() => Reflector::getParameterClassName($parameter)];
30-
})->all();
29+
if ($types[0] === null) {
30+
throw new RuntimeException('The first parameter of the given Closure is missing a type hint.');
31+
}
32+
33+
return $types[0];
3134
}
3235

3336
/**
34-
* Get the class name of the first parameter of the given Closure.
37+
* Get the class names of the first parameter of the given Closure, including union types.
3538
*
3639
* @param \Closure $closure
37-
* @return string
40+
* @return array
3841
*
3942
* @throws \ReflectionException
4043
* @throws \RuntimeException
4144
*/
42-
protected function firstClosureParameterType(Closure $closure)
45+
protected function firstClosureParameterTypes(Closure $closure)
4346
{
44-
$types = array_values($this->closureParameterTypes($closure));
47+
$reflection = new ReflectionFunction($closure);
4548

46-
if (! $types) {
49+
$types = collect($reflection->getParameters())->mapWithKeys(function ($parameter) {
50+
if ($parameter->isVariadic()) {
51+
return [$parameter->getName() => null];
52+
}
53+
54+
return [$parameter->getName() => Reflector::getParameterClassNames($parameter)];
55+
})->filter()->values()->all();
56+
57+
if (empty($types)) {
4758
throw new RuntimeException('The given Closure has no parameters.');
4859
}
4960

50-
if ($types[0] === null) {
61+
if (isset($types[0]) && empty($types[0])) {
5162
throw new RuntimeException('The first parameter of the given Closure is missing a type hint.');
5263
}
5364

5465
return $types[0];
5566
}
67+
68+
/**
69+
* Get the class names / types of the parameters of the given Closure.
70+
*
71+
* @param \Closure $closure
72+
* @return array
73+
*
74+
* @throws \ReflectionException
75+
*/
76+
protected function closureParameterTypes(Closure $closure)
77+
{
78+
$reflection = new ReflectionFunction($closure);
79+
80+
return collect($reflection->getParameters())->mapWithKeys(function ($parameter) {
81+
if ($parameter->isVariadic()) {
82+
return [$parameter->getName() => null];
83+
}
84+
85+
return [$parameter->getName() => Reflector::getParameterClassName($parameter)];
86+
})->all();
87+
}
5688
}

tests/Database/DatabaseProcessorTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function __construct()
3939
}
4040

4141
#[\ReturnTypeWillChange]
42-
public function lastInsertId(string $sequence = null)
42+
public function lastInsertId($sequence = null)
4343
{
4444
//
4545
}

tests/Integration/Foundation/DiscoverEventsTest.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,11 @@ class_alias(ListenerInterface::class, 'Tests\Integration\Foundation\Fixtures\Eve
3232
], $events);
3333
}
3434

35+
/**
36+
* @requires PHP 8
37+
*/
3538
public function testUnionEventsCanBeDiscovered()
3639
{
37-
if (version_compare(phpversion(), '8.0.0', '<')) {
38-
$this->markTestSkipped('Test uses union types.');
39-
}
40-
4140
class_alias(UnionListener::class, 'Tests\Integration\Foundation\Fixtures\EventDiscovery\UnionListeners\UnionListener');
4241

4342
$events = DiscoverEvents::within(__DIR__.'/Fixtures/EventDiscovery/UnionListeners', getcwd());
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
use Illuminate\Tests\Support\AnotherExampleParameter;
4+
use Illuminate\Tests\Support\ExampleParameter;
5+
6+
return function (ExampleParameter | AnotherExampleParameter $a, $b) {
7+
//
8+
};

tests/Support/SupportReflectsClosuresTest.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,47 @@ public function testItThrowsWhenNoFirstParameterType()
6464
});
6565
}
6666

67+
/**
68+
* @requires PHP 8
69+
*/
70+
public function testItWorksWithUnionTypes()
71+
{
72+
$types = ReflectsClosuresClass::reflectFirstAll(function (ExampleParameter $a, $b) {
73+
//
74+
});
75+
76+
$this->assertEquals([
77+
ExampleParameter::class,
78+
], $types);
79+
80+
$closure = require __DIR__.'/Fixtures/UnionTypesClosure.php';
81+
82+
$types = ReflectsClosuresClass::reflectFirstAll($closure);
83+
84+
$this->assertEquals([
85+
ExampleParameter::class,
86+
AnotherExampleParameter::class,
87+
], $types);
88+
}
89+
90+
public function testItWorksWithUnionTypesWithNoTypeHints()
91+
{
92+
$this->expectException(RuntimeException::class);
93+
94+
$types = ReflectsClosuresClass::reflectFirstAll(function ($a, $b) {
95+
//
96+
});
97+
}
98+
99+
public function testItWorksWithUnionTypesWithNoArguments()
100+
{
101+
$this->expectException(RuntimeException::class);
102+
103+
$types = ReflectsClosuresClass::reflectFirstAll(function () {
104+
//
105+
});
106+
}
107+
67108
private function assertParameterTypes($expected, $closure)
68109
{
69110
$types = ReflectsClosuresClass::reflect($closure);
@@ -85,9 +126,19 @@ public static function reflectFirst($closure)
85126
{
86127
return (new static)->firstClosureParameterType($closure);
87128
}
129+
130+
public static function reflectFirstAll($closure)
131+
{
132+
return (new static)->firstClosureParameterTypes($closure);
133+
}
88134
}
89135

90136
class ExampleParameter
91137
{
92138
//
93139
}
140+
141+
class AnotherExampleParameter
142+
{
143+
//
144+
}

0 commit comments

Comments
 (0)