diff --git a/src/MethodSignatureString.php b/src/MethodSignatureString.php index c0dbea73..a70ecb14 100644 --- a/src/MethodSignatureString.php +++ b/src/MethodSignatureString.php @@ -7,6 +7,7 @@ use Reflection; use ReflectionMethod; use ReflectionParameter; +use UnitEnum; use function implode; use function is_numeric; @@ -19,87 +20,108 @@ use const PHP_EOL; use const PHP_MAJOR_VERSION; -/** @SuppressWarnings(PHPMD.CyclomaticComplexity) */ final class MethodSignatureString { + private const PHP_VERSION_8 = 80000; + private const NULLABLE_PHP8 = 'null|'; + private const NULLABLE_PHP7 = '?'; + private const INDENT = ' '; + /** @var TypeString */ private $typeString; public function __construct(int $phpVersion) { - $nullableStr = $phpVersion >= 80000 ? 'null|' : '?'; + $nullableStr = $phpVersion >= self::PHP_VERSION_8 ? self::NULLABLE_PHP8 : self::NULLABLE_PHP7; $this->typeString = new TypeString($nullableStr); } - /** - * @psalm-suppress MixedArgument - * @psalm-suppress MixedMethodCall - */ public function get(ReflectionMethod $method): string { - $signatureParts = []; + $signatureParts = $this->getDocComment($method); + $this->addAttributes($method, $signatureParts); + $this->addAccessModifiers($method, $signatureParts); + $this->addMethodSignature($method, $signatureParts); - // PHPDocを取得 + return implode(' ', $signatureParts); + } + + /** @return array */ + private function getDocComment(ReflectionMethod $method): array + { $docComment = $method->getDocComment(); - if (is_string($docComment)) { - $signatureParts[] = $docComment . PHP_EOL; - } - // アトリビュートを取得 (PHP 8.0+ の場合のみ) - if (PHP_MAJOR_VERSION >= 8) { - /** @psalm-suppress MixedAssignment */ - foreach ($method->getAttributes() as $attribute) { - $argsList = $attribute->getArguments(); - $formattedArgs = []; + return is_string($docComment) ? [$docComment . PHP_EOL] : []; + } - foreach ($argsList as $name => $value) { - $formattedValue = preg_replace('/\s+/', ' ', var_export($value, true)); - $argRepresentation = is_numeric($name) ? $formattedValue : "{$name}: {$formattedValue}"; - $formattedArgs[] = $argRepresentation; - } + /** @param array $signatureParts */ + private function addAttributes(ReflectionMethod $method, array &$signatureParts): void + { + if (PHP_MAJOR_VERSION < 8) { + return; + } - $signatureParts[] = sprintf(' #[\\%s(%s)]', $attribute->getName(), implode(', ', $formattedArgs)) . PHP_EOL; + $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; } - if ($signatureParts) { - $signatureParts[] = ' '; // インデント追加 + if (empty($signatureParts)) { + return; } - // アクセス修飾子を取得 + $signatureParts[] = self::INDENT; + } + + /** @param array $signatureParts */ + private function addAccessModifiers(ReflectionMethod $method, array &$signatureParts): void + { $modifier = implode(' ', Reflection::getModifierNames($method->getModifiers())); + $signatureParts[] = $modifier; + } - // メソッド名とパラメータを取得 + /** @param array $signatureParts */ + private function addMethodSignature(ReflectionMethod $method, array &$signatureParts): void + { $params = []; foreach ($method->getParameters() as $param) { $params[] = $this->generateParameterCode($param); } - $returnType = ''; + $parmsList = implode(', ', $params); $rType = $method->getReturnType(); - if ($rType) { - $returnType = ': ' . ($this->typeString)($rType); - } + $return = $rType ? ': ' . ($this->typeString)($rType) : ''; - $parmsList = implode(', ', $params); + $signatureParts[] = sprintf('function %s(%s)%s', $method->getName(), $parmsList, $return); + } - $signatureParts[] = sprintf('function %s(%s)%s', $method->getName(), $parmsList, $returnType); + /** + * @param string|int $name + * @param mixed $value + */ + private function formatArg($name, $value): string + { + $formattedValue = $value instanceof UnitEnum ? + '\\' . var_export($value, true) + : preg_replace('/\s+/', '', var_export($value, true)); - return implode(' ', $signatureParts); + return is_numeric($name) ? (string) $formattedValue : "{$name}: {$formattedValue}"; } - public function generateParameterCode(ReflectionParameter $param): string + private function generateParameterCode(ReflectionParameter $param): string { $typeStr = ($this->typeString)($param->getType()); $typeStrWithSpace = $typeStr ? $typeStr . ' ' : $typeStr; - // Variadicのチェック $variadicStr = $param->isVariadic() ? '...' : ''; - - // 参照渡しのチェック $referenceStr = $param->isPassedByReference() ? '&' : ''; - - // デフォルト値のチェック $defaultStr = ''; if ($param->isDefaultValueAvailable()) { $default = var_export($param->getDefaultValue(), true); diff --git a/tests/AopCodeTest.php b/tests/AopCodeTest.php index 71e0d92f..afcf7ff0 100644 --- a/tests/AopCodeTest.php +++ b/tests/AopCodeTest.php @@ -49,7 +49,7 @@ public function testReturnType(): void public function testVariousMethodSignature(): void { $bind = new Bind(); - for ($i = 1; $i <= 22; $i++) { + for ($i = 1; $i <= 24; $i++) { $bind->bindInterceptors('method' . (string) $i, []); } @@ -83,10 +83,14 @@ public function testVariousMethodSignature(): void $this->assertStringContainsString(' /** * PHPDoc */ - #[\\Ray\\Aop\\Annotation\\FakeMarker4(array ( 0 => 1, 1 => 2, ), 3)] + #[\\Ray\\Aop\\Annotation\\FakeMarker4(array(0=>1,1=>2,), 3)] public function method21()', $code); $this->assertStringContainsString('#[\\Ray\\Aop\\Annotation\\FakeMarkerName(a: 1, b: \'string\', c: true)] public function method22()', $code); + $this->assertStringContainsString('#[\\Ray\\Aop\\Annotation\\FakeMarker5(\\Ray\\Aop\\FakePhp81Enum::Apple)] + public function method23()', $code); + $this->assertStringContainsString('#[\\Ray\\Aop\\Annotation\\FakeMarker6(fruit1: \\Ray\\Aop\\FakePhp81Enum::Apple, fruit2: \\Ray\\Aop\\FakePhp81Enum::Orange)] + public function method24()', $code); } /** @requires PHP 8.2 */ diff --git a/tests/Fake/Annotation/FakeMarker5.php b/tests/Fake/Annotation/FakeMarker5.php new file mode 100644 index 00000000..83e4e8cf --- /dev/null +++ b/tests/Fake/Annotation/FakeMarker5.php @@ -0,0 +1,20 @@ +