Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php declare(strict_types=1);/** This file is part of sebastian/code-unit.** (c) Sebastian Bergmann <sebastian@phpunit.de>** For the full copyright and license information, please view the LICENSE* file that was distributed with this source code.*/namespace SebastianBergmann\CodeUnit;use function array_keys;use function array_merge;use function array_unique;use function array_values;use function class_exists;use function explode;use function function_exists;use function interface_exists;use function ksort;use function method_exists;use function sort;use function sprintf;use function str_replace;use function strpos;use function trait_exists;use ReflectionClass;use ReflectionFunction;use ReflectionMethod;final class Mapper{/*** @psalm-return array<string,list<int>>*/public function codeUnitsToSourceLines(CodeUnitCollection $codeUnits): array{$result = [];foreach ($codeUnits as $codeUnit) {$sourceFileName = $codeUnit->sourceFileName();if (!isset($result[$sourceFileName])) {$result[$sourceFileName] = [];}$result[$sourceFileName] = array_merge($result[$sourceFileName], $codeUnit->sourceLines());}foreach (array_keys($result) as $sourceFileName) {$result[$sourceFileName] = array_values(array_unique($result[$sourceFileName]));sort($result[$sourceFileName]);}ksort($result);return $result;}/*** @throws InvalidCodeUnitException* @throws ReflectionException*/public function stringToCodeUnits(string $unit): CodeUnitCollection{if (strpos($unit, '::') !== false) {[$firstPart, $secondPart] = explode('::', $unit);if (empty($firstPart) && $this->isUserDefinedFunction($secondPart)) {return CodeUnitCollection::fromList(CodeUnit::forFunction($secondPart));}if ($this->isUserDefinedClass($firstPart)) {if ($secondPart === '<public>') {return $this->publicMethodsOfClass($firstPart);}if ($secondPart === '<!public>') {return $this->protectedAndPrivateMethodsOfClass($firstPart);}if ($secondPart === '<protected>') {return $this->protectedMethodsOfClass($firstPart);}if ($secondPart === '<!protected>') {return $this->publicAndPrivateMethodsOfClass($firstPart);}if ($secondPart === '<private>') {return $this->privateMethodsOfClass($firstPart);}if ($secondPart === '<!private>') {return $this->publicAndProtectedMethodsOfClass($firstPart);}if ($this->isUserDefinedMethod($firstPart, $secondPart)) {return CodeUnitCollection::fromList(CodeUnit::forClassMethod($firstPart, $secondPart));}}if ($this->isUserDefinedInterface($firstPart)) {return CodeUnitCollection::fromList(CodeUnit::forInterfaceMethod($firstPart, $secondPart));}if ($this->isUserDefinedTrait($firstPart)) {return CodeUnitCollection::fromList(CodeUnit::forTraitMethod($firstPart, $secondPart));}} else {if ($this->isUserDefinedClass($unit)) {$units = [CodeUnit::forClass($unit)];foreach ($this->reflectorForClass($unit)->getTraits() as $trait) {if (!$trait->isUserDefined()) {// @codeCoverageIgnoreStartcontinue;// @codeCoverageIgnoreEnd}$units[] = CodeUnit::forTrait($trait->getName());}return CodeUnitCollection::fromArray($units);}if ($this->isUserDefinedInterface($unit)) {return CodeUnitCollection::fromList(CodeUnit::forInterface($unit));}if ($this->isUserDefinedTrait($unit)) {return CodeUnitCollection::fromList(CodeUnit::forTrait($unit));}if ($this->isUserDefinedFunction($unit)) {return CodeUnitCollection::fromList(CodeUnit::forFunction($unit));}$unit = str_replace('<extended>', '', $unit);if ($this->isUserDefinedClass($unit)) {return $this->classAndParentClassesAndTraits($unit);}}throw new InvalidCodeUnitException(sprintf('"%s" is not a valid code unit',$unit));}/*** @psalm-param class-string $className** @throws ReflectionException*/private function publicMethodsOfClass(string $className): CodeUnitCollection{return $this->methodsOfClass($className, ReflectionMethod::IS_PUBLIC);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function publicAndProtectedMethodsOfClass(string $className): CodeUnitCollection{return $this->methodsOfClass($className, ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function publicAndPrivateMethodsOfClass(string $className): CodeUnitCollection{return $this->methodsOfClass($className, ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PRIVATE);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function protectedMethodsOfClass(string $className): CodeUnitCollection{return $this->methodsOfClass($className, ReflectionMethod::IS_PROTECTED);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function protectedAndPrivateMethodsOfClass(string $className): CodeUnitCollection{return $this->methodsOfClass($className, ReflectionMethod::IS_PROTECTED | ReflectionMethod::IS_PRIVATE);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function privateMethodsOfClass(string $className): CodeUnitCollection{return $this->methodsOfClass($className, ReflectionMethod::IS_PRIVATE);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function methodsOfClass(string $className, int $filter): CodeUnitCollection{$units = [];foreach ($this->reflectorForClass($className)->getMethods($filter) as $method) {if (!$method->isUserDefined()) {continue;}$units[] = CodeUnit::forClassMethod($className, $method->getName());}return CodeUnitCollection::fromArray($units);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function classAndParentClassesAndTraits(string $className): CodeUnitCollection{$units = [CodeUnit::forClass($className)];$reflector = $this->reflectorForClass($className);foreach ($this->reflectorForClass($className)->getTraits() as $trait) {if (!$trait->isUserDefined()) {// @codeCoverageIgnoreStartcontinue;// @codeCoverageIgnoreEnd}$units[] = CodeUnit::forTrait($trait->getName());}while ($reflector = $reflector->getParentClass()) {if (!$reflector->isUserDefined()) {break;}$units[] = CodeUnit::forClass($reflector->getName());foreach ($reflector->getTraits() as $trait) {if (!$trait->isUserDefined()) {// @codeCoverageIgnoreStartcontinue;// @codeCoverageIgnoreEnd}$units[] = CodeUnit::forTrait($trait->getName());}}return CodeUnitCollection::fromArray($units);}/*** @psalm-param class-string $className** @throws ReflectionException*/private function reflectorForClass(string $className): ReflectionClass{try {return new ReflectionClass($className);// @codeCoverageIgnoreStart} catch (\ReflectionException $e) {throw new ReflectionException($e->getMessage(),(int) $e->getCode(),$e);}// @codeCoverageIgnoreEnd}/*** @throws ReflectionException*/private function isUserDefinedFunction(string $functionName): bool{if (!function_exists($functionName)) {return false;}try {return (new ReflectionFunction($functionName))->isUserDefined();// @codeCoverageIgnoreStart} catch (\ReflectionException $e) {throw new ReflectionException($e->getMessage(),(int) $e->getCode(),$e);}// @codeCoverageIgnoreEnd}/*** @throws ReflectionException*/private function isUserDefinedClass(string $className): bool{if (!class_exists($className)) {return false;}try {return (new ReflectionClass($className))->isUserDefined();// @codeCoverageIgnoreStart} catch (\ReflectionException $e) {throw new ReflectionException($e->getMessage(),(int) $e->getCode(),$e);}// @codeCoverageIgnoreEnd}/*** @throws ReflectionException*/private function isUserDefinedInterface(string $interfaceName): bool{if (!interface_exists($interfaceName)) {return false;}try {return (new ReflectionClass($interfaceName))->isUserDefined();// @codeCoverageIgnoreStart} catch (\ReflectionException $e) {throw new ReflectionException($e->getMessage(),(int) $e->getCode(),$e);}// @codeCoverageIgnoreEnd}/*** @throws ReflectionException*/private function isUserDefinedTrait(string $traitName): bool{if (!trait_exists($traitName)) {return false;}try {return (new ReflectionClass($traitName))->isUserDefined();// @codeCoverageIgnoreStart} catch (\ReflectionException $e) {throw new ReflectionException($e->getMessage(),(int) $e->getCode(),$e);}// @codeCoverageIgnoreEnd}/*** @throws ReflectionException*/private function isUserDefinedMethod(string $className, string $methodName): bool{if (!class_exists($className)) {// @codeCoverageIgnoreStartreturn false;// @codeCoverageIgnoreEnd}if (!method_exists($className, $methodName)) {// @codeCoverageIgnoreStartreturn false;// @codeCoverageIgnoreEnd}try {return (new ReflectionMethod($className, $methodName))->isUserDefined();// @codeCoverageIgnoreStart} catch (\ReflectionException $e) {throw new ReflectionException($e->getMessage(),(int) $e->getCode(),$e);}// @codeCoverageIgnoreEnd}}