Skip to content

Commit 8d89f04

Browse files
committed
Adds support for named arguments
1 parent a959588 commit 8d89f04

File tree

4 files changed

+62
-5
lines changed

4 files changed

+62
-5
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ echo $closure(); // james;
5151

5252
### Caveats
5353

54-
Creating **anonymous classes** within closures is not supported.
54+
1. Creating **anonymous classes** within closures is not supported.
55+
2. Using attributes within closures is not supported.
5556

5657
## Contributing
5758

src/Support/ReflectionClosure.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -679,10 +679,18 @@ public function getCode()
679679

680680
if (PHP_VERSION_ID >= 80100) {
681681
$attributesCode = array_map(function ($attribute) {
682+
$arguments = $attribute->getArguments();
683+
682684
$name = $attribute->getName();
683-
$arguments = implode(', ', array_map(function ($argument) {
684-
return sprintf("'%s'", str_replace("'", "\\'", $argument));
685-
}, $attribute->getArguments()));
685+
$arguments = implode(', ', array_map(function ($argument, $key) {
686+
$argument = sprintf("'%s'", str_replace("'", "\\'", $argument));
687+
688+
if (is_string($key)) {
689+
$argument = sprintf('%s: %s', $key, $argument);
690+
}
691+
692+
return $argument;
693+
}, $arguments, array_keys($arguments)));
686694

687695
return "#[$name($arguments)]";
688696
}, $this->getAttributes());

tests/ReflectionClosurePhp81Test.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,23 @@ function () {
318318
expect($f)->toBeCode($e);
319319
});
320320

321+
test('function attributes with named arguments', function () {
322+
$model = new Model();
323+
324+
$f = #[MyAttribute(string: 'My " \' Argument 1', model:Model::class)] function () {
325+
return false;
326+
};
327+
328+
$e = <<<EOF
329+
#[MyAttribute(string: 'My " \' Argument 1', model: 'Tests\Fixtures\Model')]
330+
function () {
331+
return false;
332+
}
333+
EOF;
334+
335+
expect($f)->toBeCode($e);
336+
});
337+
321338
test('function attributes with first-class callable with methods', function () {
322339
$model = new Model();
323340

tests/SerializerPhp81Test.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,34 @@ enum SerializerScopedBackedEnum: string {
345345
expect($f())->toBeFalse();
346346
})->with('serializers');
347347

348+
test('function attributes with named arguments', function () {
349+
$model = new Model();
350+
351+
$f = #[MyAttribute(string: 'My " \' Argument 1', model:Model::class)] function () {
352+
return false;
353+
};
354+
355+
$f = s($f);
356+
357+
$reflector = new ReflectionFunction($f);
358+
359+
expect($reflector->getAttributes())->sequence(function ($attribute) {
360+
361+
$attribute
362+
->getName()->toBe(MyAttribute::class)
363+
->getArguments()->toBe([
364+
'string' => 'My " \' Argument 1',
365+
'model' => Model::class,
366+
]);
367+
368+
expect($attribute->value->newInstance())
369+
->string->toBe('My " \' Argument 1')
370+
->model->toBe(Model::class);
371+
});
372+
373+
expect($f())->toBeFalse();
374+
})->with('serializers');
375+
348376
test('function attributes with first-class callable with methods', function () {
349377
$f = (new SerializerPhp81Controller())->publicGetter(...);
350378

@@ -443,6 +471,9 @@ public function getSelf(self $instance): self
443471
#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION)]
444472
class MyAttribute
445473
{
446-
// ..
474+
public function __construct(public $string, public $model)
475+
{
476+
// ..
477+
}
447478
}
448479

0 commit comments

Comments
 (0)