Skip to content

Commit

Permalink
fix: ReflectionAttribute::newInstance() with nested class using named…
Browse files Browse the repository at this point in the history
… arguments
  • Loading branch information
enumag authored and ondrejmirtes committed Sep 18, 2023
1 parent b187d7e commit 8d751dd
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/NodeCompiler/CompileNodeToValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,10 @@ private function compileNew(Node\Expr\New_ $node, CompilerContext $context): obj
throw Exception\UnableToCompileNode::becauseOfClassCannotBeLoaded($context, $node, $className);
}

$arguments = array_map(fn (Node\Arg $arg): mixed => $this($arg->value, $context)->value, $node->args);
$arguments = [];
foreach ($node->args as $argNo => $arg) {
$arguments[(($argName = $arg->name) ? $argName->toString() : null) ?? $argNo] = $this($arg->value, $context)->value;
}

return new $className(...$arguments);
}
Expand Down
20 changes: 20 additions & 0 deletions test/unit/Fixture/Attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,23 @@ class ClassWithAttributeThatAcceptsArgument
{

}

class NestedClassUsingNamedArguments
{
public function __construct(public ?SomeEnum $e = null, public string $s = '')
{
}
}

#[Attribute]
class AttributeThatHasNestedClassUsingNamedArguments
{
public function __construct(public NestedClassUsingNamedArguments $nested)
{
}
}

#[AttributeThatHasNestedClassUsingNamedArguments(new NestedClassUsingNamedArguments(s: 'string'))]
class ClassWithAttributeThatHasNestedClassUsingNamedArguments
{
}
22 changes: 22 additions & 0 deletions test/unit/Reflection/Adapter/ReflectionAttributeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
use Roave\BetterReflection\SourceLocator\Type\SingleFileSourceLocator;
use Roave\BetterReflectionTest\BetterReflectionSingleton;
use Roave\BetterReflectionTest\Fixture\AttributeThatAcceptsArgument;
use Roave\BetterReflectionTest\Fixture\AttributeThatHasNestedClassUsingNamedArguments;
use Roave\BetterReflectionTest\Fixture\AttributeThatNeedsNamedArguments;
use Roave\BetterReflectionTest\Fixture\ClassWithAttributeThatAcceptsArgument;
use Roave\BetterReflectionTest\Fixture\ClassWithAttributeThatHasNestedClassUsingNamedArguments;
use Roave\BetterReflectionTest\Fixture\ClassWithAttributeThatNeedsNamedArguments;
use Roave\BetterReflectionTest\Fixture\SomeEnum;
use function array_combine;
use function array_map;
Expand Down Expand Up @@ -98,4 +102,22 @@ public function testNewInstanceWithEnum(): void
$this->assertSame('ONE', $instance->e->name);
$this->assertSame(1, $instance->e->value);
}

public function testNewInstanceWithNestedClassUsingNamedArguments(): void
{
$astLocator = BetterReflectionSingleton::instance()->astLocator();
$path = __DIR__ . '/../../Fixture/Attributes.php';
require_once($path);

$betterReflection = BetterReflectionSingleton::instance();
$reflector = new DefaultReflector(new AggregateSourceLocator([new SingleFileSourceLocator($path, $astLocator), new PhpInternalSourceLocator($astLocator, $betterReflection->sourceStubber())]));
$reflection = $reflector->reflectClass(ClassWithAttributeThatHasNestedClassUsingNamedArguments::class);
$attributes = $reflection->getAttributesByName(AttributeThatHasNestedClassUsingNamedArguments::class);
$this->assertCount(1, $attributes);
$adapter = new ReflectionAttributeAdapter($attributes[0]);
$instance = $adapter->newInstance();
$this->assertInstanceOf(AttributeThatHasNestedClassUsingNamedArguments::class, $instance);
$this->assertNull($instance->nested->e);
$this->assertSame('string', $instance->nested->s);
}
}

0 comments on commit 8d751dd

Please sign in to comment.