Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
}
],
"require": {
"php": ">=7.4",
"roave/better-reflection": "^4.0@dev",
"php": ">=8.2",
"roave/better-reflection": "^6.22.0",
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed usages of this lib, to review and to remove once all done

"phpdocumentor/type-resolver": "^1.0@dev"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.4",
"phpstan/phpstan": "^0.12.0@dev",
"phpstan/phpstan": "^1.10.56",
"phpunit/phpcov": "^8.2",
"phpunit/phpunit": "^9.2@dev",
"roave/security-advisories": "dev-master",
Expand Down
239 changes: 239 additions & 0 deletions src/PhpGenerator/Helper/ReflectionHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
<?php

declare(strict_types=1);

namespace Sidux\PhpGenerator\Helper;

use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\BetterReflection\BetterReflection;
use ReflectionClass;
use ReflectionFunction;
use ReflectionParameter;
use ReflectionProperty;
use ReflectionMethod;

final class ReflectionHelper
{
public static function getBodyCode(ReflectionFunction|ReflectionMethod|\PHPStan\BetterReflection\Reflection\ReflectionFunction $reflection, bool $isInterface = false): string
{
if ($isInterface || ($reflection instanceof ReflectionMethod && $reflection->isAbstract())) {
return '';
}

$filename = $reflection->getFileName();

if ($filename === false) {
throw new \LogicException("Filename is not set");
}

$file = file($filename);

if ($file === false) {
throw new \LogicException("Unable to open file {$filename}.");
}

$startLine = self::getBodyCodeStartLine($reflection->getName(), $file);
$endLine = self::getBodyCodeEndLine($reflection->getName(), $file);

$length = $endLine - $startLine + 1;

if ($length <= 2) {
$length = 0;
}

$code = \array_slice($file, $startLine, $length);

return trim(preg_replace('/\s+{\n|\s+}\n/', '', implode('', $code)));
}

public static function getBodyCodeStartLine(string $functionOrMethodName, array $file): int
{
$startLine = 0;
$found = false;

foreach ($file as $lineNumber => $line) {
if (str_contains($line, $functionOrMethodName)) {
$startLine = $lineNumber;
$found = true;
}

if ($found && str_contains($line, '{')) {
$startLine = $lineNumber;
break;
}
}

return $startLine;
}

public static function getBodyCodeEndLine(string $functionOrMethodName, array $file): int
{
$endLine = 0;
$found = false;

foreach ($file as $lineNumber => $line) {
if (str_contains($line, $functionOrMethodName)) {
$endLine = $lineNumber;
$found = true;
}

if ($found && str_contains($line, '}')) {
$endLine = $lineNumber;
break;
}
}

return $endLine;
}

public static function getDocBlockReturnTypes(ReflectionFunction|ReflectionMethod|\PHPStan\BetterReflection\Reflection\ReflectionFunction $reflection): array
{
$docBlockFactory = DocBlockFactory::createInstance();
$typeResolver = new TypeResolver();
$docComment = $reflection->getDocComment();
$context = $reflection->getNamespaceName() ? new Context($reflection->getNamespaceName()) : null;

if ($docComment === false) {
return [];
}

$returnTags = $docBlockFactory
->create($docComment, $context)
->getTagsByName('return');

$types = [];

foreach ($returnTags as $returnTag) {
/** @var Return_ $returnTag */
$returnTypes = explode('|', (string)$returnTag->getType());

foreach ($returnTypes as $returnType) {
$type = $typeResolver->resolve($returnType, $context);
$types[] = $type;
}
}

return $types;
}

public static function getDocBlockTypes(ReflectionParameter|ReflectionProperty|\PHPStan\BetterReflection\Reflection\ReflectionParameter $reflection): array
{
$docBlockFactory = DocBlockFactory::createInstance();
$typeResolver = new TypeResolver();

if ($reflection instanceof ReflectionProperty) {
$docComment = $reflection->getDocComment();
$context = new Context($reflection->getDeclaringClass()->getNamespaceName());

} else {
$docComment = $reflection->getDeclaringFunction()->getDocComment();
$namespace = $reflection->getDeclaringFunction()->getNamespaceName();
$context = $namespace ? new Context($reflection->getDeclaringFunction()->getNamespaceName()) : null;
}

if ($docComment === false) {
return [];
}

$paramTags = $docBlockFactory
->create($docComment, $context)
->getTagsByName('param');

$types = [];

foreach ($paramTags as $paramTag) {
/** @var \phpDocumentor\Reflection\DocBlock\Tags\Param $paramTag */
$paramTypes = explode('|', (string)$paramTag->getType());

foreach ($paramTypes as $paramType) {
$type = $typeResolver->resolve($paramType, $context);
$types[] = $type;
}
}

return $types;
}

/**
* @throws \Exception
*/
public static function createReflectionMethodFromName(string $className, string $methodName): ReflectionMethod
{
try {
return self::createClassFromName($className)->getMethod($methodName);
} catch (\ReflectionException) {
throw new \Exception(sprintf('Could not find class: %s', $className));
}
}

/**
* @throws \Exception
*/
public static function createReflectionFunctionFromName(string $functionName): \PHPStan\BetterReflection\Reflection\ReflectionFunction
{
return (new BetterReflection())->reflector()->reflectFunction($functionName);
}

/**
* @throws \ReflectionException
*/
public static function createClassFromName(string $className): ReflectionClass
{
return new ReflectionClass($className);
}

/**
* @throws \ReflectionException
*/
public static function createFunctionFromClosure(\Closure $closure): ReflectionFunction
{
return new ReflectionFunction($closure);
}

public static function createClassFromInstance(object $instance): ReflectionClass
{
return new ReflectionClass($instance);
}

public static function createPropertyFromName(string $className, string $propertyName): ReflectionProperty
{
return self::createClassFromName($className)->getProperty($propertyName);
}

public static function createPropertyFromInstance(object $instance, string $propertyName): ReflectionProperty
{
return self::createClassFromInstance($instance)->getProperty($propertyName);
}

/**
* @throws \ReflectionException
*/
public static function createParameterFromInstanceAndMethod(object $instance, string $methodName, string $parameterName): ReflectionParameter
{
$parameters = self::createClassFromInstance($instance)->getMethod($methodName)->getParameters();

foreach ($parameters as $parameter) {
if ($parameter->getName() === $parameterName) {
return $parameter;
}
}

throw new \ReflectionException(sprintf('Could not find parameter: %s', $parameterName));
}

public static function createParameterFromClassNameAndMethod(string $className, string $methodName, string $parameterName): ReflectionParameter
{
$parameters = self::createClassFromName($className)->getMethod($methodName)->getParameters();

foreach ($parameters as $parameter) {
if ($parameter->getName() === $parameterName) {
return $parameter;
}
}

throw new \ReflectionException(sprintf('Could not find parameter: %s', $parameterName));
}
}
8 changes: 4 additions & 4 deletions src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Sidux\PhpGenerator\Helper\Traits;

use Roave\BetterReflection\Reflection\ReflectionClass;
use Sidux\PhpGenerator\Helper\PhpHelper;
use Sidux\PhpGenerator\Helper\ReflectionHelper;

trait MethodOverloadAwareTrait
{
Expand All @@ -29,16 +29,16 @@ protected static function buildMethodNameWithArgsTypes(string $baseName, array $
foreach ($args as $i => $arg) {
$type = \gettype($arg);
if ('object' === $type) {
$class = ReflectionClass::createFromInstance($arg);
$class = ReflectionHelper::createClassFromInstance($arg);
$types[$i][] = $class->getShortName();
$types[$i] = array_merge(
$types[$i],
$class->getInterfaceNames(),
$class->getParentClassNames()
[$class->getParentClass() ?? $class->getParentClass()->getName()]
);
}
$types[$i][] = $type;
$types[$i] = array_map([PhpHelper::class, 'extractShortName'], $types[$i]);
$types[$i] = array_map(PhpHelper::extractShortName(...), $types[$i]);
}

$argsNumber = \count($args);
Expand Down
6 changes: 3 additions & 3 deletions src/PhpGenerator/Helper/VarPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private static function dumpArray(array &$var, array $parents, int $level, int $
unset($v);

array_pop($parents);
$wrap = false !== strpos($outInline, "\n") || $level * self::INDENT_LENGTH + $column + \strlen($outInline) + 3 > self::$wrapLength;
$wrap = str_contains($outInline, "\n") || $level * self::INDENT_LENGTH + $column + \strlen($outInline) + 3 > self::$wrapLength;

return '[' . ($wrap ? $outWrapped : $outInline) . ']';
}
Expand All @@ -128,7 +128,7 @@ private static function dumpObject($var, array $parents, int $level): string
throw new \InvalidArgumentException('Cannot dump closure.');
}

$class = \get_class($var);
$class = $var::class;
if ((new ReflectionObject($var))->isAnonymous()) {
throw new \InvalidArgumentException('Cannot dump anonymous class.');
}
Expand Down Expand Up @@ -170,6 +170,6 @@ private static function dumpObject($var, array $parents, int $level): string

return \stdClass::class === $class
? "(object) [$out]"
: __CLASS__ . "::createObject('$class', [$out])";
: self::class . "::createObject('$class', [$out])";
}
}
4 changes: 2 additions & 2 deletions src/PhpGenerator/Model/Constant.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
use Sidux\PhpGenerator\Model\Contract\Member;
use Sidux\PhpGenerator\Model\Contract\ValueAware;

class Constant extends Member implements ValueAware
class Constant extends Member implements ValueAware, \Stringable
{
use Part\NamespaceAwareTrait;
use Part\VisibilityAwareTrait;
use Part\CommentAwareTrait;
use Part\ValueAwareTrait;

public const DEFAULT_VISIBILITY = Struct::PUBLIC;
final public const DEFAULT_VISIBILITY = Struct::PUBLIC;

public static function create(string $name): self
{
Expand Down
7 changes: 3 additions & 4 deletions src/PhpGenerator/Model/Contract/TypeAware.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Sidux\PhpGenerator\Model\Contract;

use phpDocumentor\Reflection\Type as DocType;
use Roave\BetterReflection\Reflection\ReflectionType;
use Sidux\PhpGenerator\Model\Type;

interface TypeAware
Expand All @@ -25,19 +24,19 @@ public function getTypeHint(): ?string;
public function getTypes(): array;

/**
* @param array<string|int, null|string|NamespaceAware|Type|ReflectionType|DocType> $types
* @param array<string|int, null|string|NamespaceAware|Type|\ReflectionType|DocType> $types
*/
public function setTypes(array $types);

public function isNullable(): bool;

/**
* @param array<string|int, null|string|NamespaceAware|Type|ReflectionType|DocType> $types
* @param array<string|int, null|string|NamespaceAware|Type|\ReflectionType|DocType> $types
*/
public function addTypes(array $types);

/**
* @param null|string|NamespaceAware|Type|ReflectionType|DocType $type
* @param null|string|NamespaceAware|Type|\ReflectionType|DocType $type
*/
public function addType($type);
}
27 changes: 27 additions & 0 deletions src/PhpGenerator/Model/EnumCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Sidux\PhpGenerator\Model;

use Sidux\PhpGenerator\Model\Contract\Member;

class EnumCase extends Member implements \Stringable
{
use Part\NamespaceAwareTrait;
use Part\CommentAwareTrait;
use Part\ValueAwareTrait;

public static function create(string $name): self
{
return new self($name);
}

public function __toString()
{
$output = '';
$output .= "case {$this->getName()} = {$this->getValue()};";

return $output;
}
}
Loading