Skip to content

Commit

Permalink
Merge pull request #227 from ray-di/attr-param
Browse files Browse the repository at this point in the history
Supports method parameter attributes
  • Loading branch information
koriym authored Nov 15, 2024
2 parents 5790b6d + 6439e7f commit 10e8579
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 71 deletions.
51 changes: 39 additions & 12 deletions src/MethodSignatureString.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Ray\Aop;

use Reflection;
use ReflectionAttribute;
use ReflectionMethod;
use ReflectionParameter;
use UnitEnum;
Expand All @@ -23,17 +24,16 @@

final class MethodSignatureString
{
private const PHP_VERSION_8 = 80000;
private const NULLABLE_PHP8 = 'null|';
private const NULLABLE_PHP7 = '?';
private const INDENT = ' ';

/** @var TypeString */
/** @var TypeString */
private $typeString;

public function __construct(int $phpVersion)
{
$nullableStr = $phpVersion >= self::PHP_VERSION_8 ? self::NULLABLE_PHP8 : self::NULLABLE_PHP7;
$nullableStr = $phpVersion >= 80000 ? self::NULLABLE_PHP8 : self::NULLABLE_PHP7;
$this->typeString = new TypeString($nullableStr);
}

Expand Down Expand Up @@ -69,14 +69,7 @@ private function addAttributes(ReflectionMethod $method, array &$signatureParts)

$attributes = $method->getAttributes();
foreach ($attributes as $attribute) {
$argsList = $attribute->getArguments();
$formattedArgs = [];
/** @var mixed $value */
foreach ($argsList as $name => $value) {
$formattedArgs[] = $this->formatArg($name, $value);
}

$signatureParts[] = sprintf(' #[\\%s(%s)]', $attribute->getName(), implode(', ', $formattedArgs)) . PHP_EOL;
$signatureParts[] = sprintf(' #[%s]', $this->formatAttributeStr($attribute)) . PHP_EOL;
}

if (empty($signatureParts)) {
Expand All @@ -86,6 +79,19 @@ private function addAttributes(ReflectionMethod $method, array &$signatureParts)
$signatureParts[] = self::INDENT;
}

/** @param ReflectionAttribute<object> $attribute */
private function formatAttributeStr(ReflectionAttribute $attribute): string
{
$argsList = $attribute->getArguments();
$formattedArgs = [];
/** @var scalar $value */
foreach ($argsList as $name => $value) {
$formattedArgs[] = $this->formatArg($name, $value);
}

return sprintf('\\%s(%s)', $attribute->getName(), implode(', ', $formattedArgs));
}

/**
* @param array<string> $signatureParts
*
Expand Down Expand Up @@ -139,6 +145,7 @@ private function formatArg($name, $value): string

private function generateParameterCode(ReflectionParameter $param): string
{
$attributesStr = $this->getAttributeStr($param);
$typeStr = ($this->typeString)($param->getType());
$typeStrWithSpace = $typeStr ? $typeStr . ' ' : $typeStr;
$variadicStr = $param->isVariadic() ? '...' : '';
Expand All @@ -149,6 +156,26 @@ private function generateParameterCode(ReflectionParameter $param): string
$defaultStr = ' = ' . str_replace(["\r", "\n"], '', $default);
}

return "{$typeStrWithSpace}{$referenceStr}{$variadicStr}\${$param->getName()}{$defaultStr}";
return "{$attributesStr}{$typeStrWithSpace}{$referenceStr}{$variadicStr}\${$param->getName()}{$defaultStr}";
}

public function getAttributeStr(ReflectionParameter $param): string
{
if (PHP_MAJOR_VERSION < 8) {
return '';
}

$attributesStr = '';
$attributes = $param->getAttributes();
if (! empty($attributes)) {
$attributeStrings = [];
foreach ($attributes as $attribute) {
$attributeStrings[] = sprintf('#[%s]', $this->formatAttributeStr($attribute));
}

$attributesStr = implode(' ', $attributeStrings) . ' ';
}

return $attributesStr;
}
}
3 changes: 2 additions & 1 deletion tests/AopCodeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function testReturnType(): void
public function testVariousMethodSignature(): void
{
$bind = new Bind();
for ($i = 1; $i <= 24; $i++) {
for ($i = 1; $i <= 25; $i++) {
$bind->bindInterceptors('method' . (string) $i, []);
}

Expand Down Expand Up @@ -91,6 +91,7 @@ public function method22()', $code);
public function method23()', $code);
$this->assertStringContainsString('#[\\Ray\\Aop\\Annotation\\FakeMarker6(fruit1: \\Ray\\Aop\\FakePhp81Enum::Apple, fruit2: \\Ray\\Aop\\FakePhp81Enum::Orange)]
public function method24()', $code);
$this->assertStringContainsString("public function method25(#[\Ray\Aop\Attribute\FakeAttr1()] \$a, #[\Ray\Aop\Attribute\FakeAttr1()] #[\Ray\Aop\Attribute\FakeAttr2(name: 'famicon', age: 40)] \$b): void", $code);
}

/** @requires PHP 8.2 */
Expand Down
10 changes: 10 additions & 0 deletions tests/Fake/Attribute/FakeAttr1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Ray\Aop\Attribute;

use Attribute;

#[Attribute]
final class FakeAttr1
{
}
15 changes: 15 additions & 0 deletions tests/Fake/Attribute/FakeAttr2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Ray\Aop\Attribute;

use Attribute;

#[Attribute]
final class FakeAttr2
{
private function __construct(
private string $name,
private int $age
){
}
}
10 changes: 10 additions & 0 deletions tests/Fake/FakePhp8Types.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Ray\Aop\Annotation\FakeMarker5;
use Ray\Aop\Annotation\FakeMarker6;
use Ray\Aop\Annotation\FakeMarkerName;
use Ray\Aop\Attribute\FakeAttr1;
use Ray\Aop\Attribute\FakeAttr2;

class FakePhp8Types implements FakeNullInterface, \Ray\Aop\FakeNullInterface1
{
Expand Down Expand Up @@ -69,4 +71,12 @@ public function method23() {}

#[FakeMarker6(fruit1: FakePhp81Enum::Apple, fruit2: FakePhp81Enum::Orange)]
public function method24() {}

// Method with attribute
public function method25(
#[FakeAttr1]
$a,
#[FakeAttr1, FakeAttr2(name: 'famicon', age: 40)]
$b
): void {}
}
Loading

0 comments on commit 10e8579

Please sign in to comment.