From 437cec0a59f14ff5188a604584b3f3228f6b8f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Hansl=C3=ADk?= Date: Mon, 6 Dec 2021 16:58:33 +0100 Subject: [PATCH 1/2] Removed the ability to monkey patch the code --- README.md | 1 - UPGRADE.md | 1 + demo/monkey-patching/MyClass.php | 8 - demo/monkey-patching/index.php | 25 --- docs/features.md | 19 --- docs/how-it-works.md | 2 +- docs/reflection-modification.md | 63 ------- src/Reflection/ReflectionClass.php | 106 ------------ src/Reflection/ReflectionFunctionAbstract.php | 128 -------------- src/Reflection/ReflectionObject.php | 28 ---- src/Reflection/ReflectionParameter.php | 16 -- src/Reflection/ReflectionProperty.php | 42 ----- test/compat/MonkeyPatchFunction.phpt | 42 ----- test/demo/check-demo.sh | 1 - test/unit/Reflection/ReflectionClassTest.php | 106 ------------ .../ReflectionFunctionAbstractTest.php | 158 ------------------ .../Reflection/ReflectionParameterTest.php | 37 ---- .../Reflection/ReflectionPropertyTest.php | 78 --------- 18 files changed, 2 insertions(+), 859 deletions(-) delete mode 100644 demo/monkey-patching/MyClass.php delete mode 100644 demo/monkey-patching/index.php delete mode 100644 docs/reflection-modification.md delete mode 100644 test/compat/MonkeyPatchFunction.phpt diff --git a/README.md b/README.md index e487a85c2..551ed104e 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,6 @@ $classInfo = (new BetterReflection()) * [The features](docs/features.md) * [Test suite](https://github.com/Roave/BetterReflection/blob/master/test/README.md) * [AST extraction](docs/ast-extraction.md) -* [Reflection modification](docs/reflection-modification.md) ## Upgrading diff --git a/UPGRADE.md b/UPGRADE.md index 17c2a5df1..dfdf8189b 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -6,6 +6,7 @@ or backwards compatibility (BC) breakages occur. ## 5.0.0 ### BC Breaks +* Removed the ability to monkey patch the code. * Doc block parsing has been removed: * `\Roave\BetterReflection\Reflection\ReflectionMethod::getDocBlockReturnTypes()` * `\Roave\BetterReflection\Reflection\ReflectionFunction::getDocBlockReturnTypes()` diff --git a/demo/monkey-patching/MyClass.php b/demo/monkey-patching/MyClass.php deleted file mode 100644 index f65393c73..000000000 --- a/demo/monkey-patching/MyClass.php +++ /dev/null @@ -1,8 +0,0 @@ -astLocator()) -))->reflectClass('MyClass'); -$loader->addClass($classInfo); - -// Override the body...! -$classInfo->getMethod('foo')->setBodyFromClosure(function () { - return 4; -}); - -$c = new MyClass(); -echo $c->foo() . "\n"; // should be 4...!?!?? diff --git a/docs/features.md b/docs/features.md index 734e456c7..3c2d6cd1e 100644 --- a/docs/features.md +++ b/docs/features.md @@ -29,22 +29,3 @@ These act in the same way as the core reflection API, except they return a ```php $reflectionType = $parameterInfo->getType(); ``` - -However, Better Reflection also gives the ability to change, and remove type declarations. Removing these types might -be useful if you want to make code written for PHP 7 work in PHP 5 for example, or setting new types to do the -opposite. For example, you might want to set the PHP 7 return type declaration to that defined in the PHP DocBlock. - -```php -// Change a function to ensure it returns an integer -$functionInfo->setReturnType('int'); - -// Remove the return type declaration -$functionInfo->removeReturnType(); -``` - -You can do similar things with parameter types also: - -```php -$parameterInfo->setType('int'); -$parameterInfo->removeType(); -``` diff --git a/docs/how-it-works.md b/docs/how-it-works.md index 5c93b6199..d34b8b622 100644 --- a/docs/how-it-works.md +++ b/docs/how-it-works.md @@ -66,4 +66,4 @@ Locators is loaded into an [AST format](https://en.wikipedia.org/wiki/Abstract_s Internally to the `Reflection*` classes in Better Reflection, we cleverly hold the AST as the main property. All reflection, analysis and modification is done directly to this AST. Therefore it is possible to unparse or export the -AST back into code - and thus execute monkey patched code. +AST back into code. diff --git a/docs/reflection-modification.md b/docs/reflection-modification.md deleted file mode 100644 index 977e195f9..000000000 --- a/docs/reflection-modification.md +++ /dev/null @@ -1,63 +0,0 @@ -# Reflection Modification - -## Replacing a function or method body - -It is possible in Better Reflection to replace the body statements of a function in the reflection - in essence, giving -the ability to monkey patch the code. - -Given the following class under reflection: - -```php -class MyClass -{ - public function foo() - { - return 5; - } -} -``` - -You can replace the body of the function like so: - -```php -reflector()->reflectClass('MyClass'); - -$classInfo->getMethod('foo')->setBody(function () { - return 4; -}); -``` - -This does not take immediate effect on execution - and in fact, if the class is already loaded, it is impossible to -overwrite the in-memory class (this is a restriction in PHP itself). However, if you have reflected on this class in -such a way that it is not already in memory, it is possible to load this class using Better Reflection's own autoload -system (make sure this is added *after* any other autoloader, otherwise it may not behave correctly. - -```php -addClass($classInfo); - -$c = new MyClass(); -var_dump($c->foo()); // This will now be 4, not 5... -``` - -But, you probably shouldn't do this ;) - -Loader methods available are: - - * `FileCacheLoader` - cache the file contents (no cache invalidation). Example usage is above; it's recommended to use - the `defaultFileCacheLoader` static constructor to simplify creation. Pass the directory to store cached files - as the parameter. - * `EvalCacheLoader` - as the naming suggests, uses `eval` to bring the class into scope. This is not ideal if you're - after performance. diff --git a/src/Reflection/ReflectionClass.php b/src/Reflection/ReflectionClass.php index dc5dcb930..7d2342cb8 100644 --- a/src/Reflection/ReflectionClass.php +++ b/src/Reflection/ReflectionClass.php @@ -14,12 +14,10 @@ use PhpParser\Node\Stmt\Interface_ as InterfaceNode; use PhpParser\Node\Stmt\Namespace_ as NamespaceNode; use PhpParser\Node\Stmt\Namespace_; -use PhpParser\Node\Stmt\Property as PropertyNode; use PhpParser\Node\Stmt\Trait_ as TraitNode; use PhpParser\Node\Stmt\TraitUse; use ReflectionClass as CoreReflectionClass; use ReflectionException; -use ReflectionProperty as CoreReflectionProperty; use Roave\BetterReflection\BetterReflection; use Roave\BetterReflection\Reflection\Annotation\AnnotationHelper; use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper; @@ -1660,108 +1658,4 @@ public function getAttributesByInstance(string $className): array { return ReflectionAttributeHelper::filterAttributesByInstance($this->getAttributes(), $className); } - - /** - * Set whether this class is final or not - * - * @throws NotAClassReflection - */ - public function setFinal(bool $isFinal): void - { - if (! $this->node instanceof ClassNode) { - throw NotAClassReflection::fromReflectionClass($this); - } - - if ($isFinal === true) { - $this->node->flags |= ClassNode::MODIFIER_FINAL; - - return; - } - - $this->node->flags &= ~ClassNode::MODIFIER_FINAL; - } - - /** - * Remove the named method from the class. - * - * Returns true if method was successfully removed. - * Returns false if method was not found, or could not be removed. - */ - public function removeMethod(string $methodName): bool - { - $lowerName = strtolower($methodName); - foreach ($this->node->getMethods() as $key => $stmt) { - if ($lowerName === $stmt->name->toLowerString()) { - unset($this->node->stmts[$key]); - $this->cachedMethods = null; - - return true; - } - } - - return false; - } - - /** - * Add a new method to the class. - */ - public function addMethod(string $methodName): void - { - $this->node->stmts[] = new ClassMethod($methodName); - $this->cachedMethods = null; - } - - /** - * Add a new property to the class. - * - * Visibility defaults to \ReflectionProperty::IS_PUBLIC, or can be ::IS_PROTECTED or ::IS_PRIVATE. - */ - public function addProperty( - string $propertyName, - int $visibility = CoreReflectionProperty::IS_PUBLIC, - bool $static = false, - ): void { - $type = 0; - switch ($visibility) { - case CoreReflectionProperty::IS_PRIVATE: - $type |= ClassNode::MODIFIER_PRIVATE; - break; - case CoreReflectionProperty::IS_PROTECTED: - $type |= ClassNode::MODIFIER_PROTECTED; - break; - default: - $type |= ClassNode::MODIFIER_PUBLIC; - break; - } - - if ($static) { - $type |= ClassNode::MODIFIER_STATIC; - } - - $this->node->stmts[] = new PropertyNode($type, [new Node\Stmt\PropertyProperty($propertyName)]); - $this->cachedProperties = null; - $this->cachedImmediateProperties = null; - } - - /** - * Remove a property from the class. - */ - public function removeProperty(string $propertyName): bool - { - $lowerName = strtolower($propertyName); - - foreach ($this->node->getProperties() as $key => $stmt) { - $propertyNames = array_map(static fn (Node\Stmt\PropertyProperty $propertyProperty): string => $propertyProperty->name->toLowerString(), $stmt->props); - - if (in_array($lowerName, $propertyNames, true)) { - $this->cachedProperties = null; - $this->cachedImmediateProperties = null; - unset($this->node->stmts[$key]); - - return true; - } - } - - return false; - } } diff --git a/src/Reflection/ReflectionFunctionAbstract.php b/src/Reflection/ReflectionFunctionAbstract.php index 2a85c228c..5fc0f894a 100644 --- a/src/Reflection/ReflectionFunctionAbstract.php +++ b/src/Reflection/ReflectionFunctionAbstract.php @@ -4,27 +4,17 @@ namespace Roave\BetterReflection\Reflection; -use Closure; use PhpParser\Comment\Doc; use PhpParser\Node; use PhpParser\Node\Expr\Yield_ as YieldNode; use PhpParser\Node\Expr\YieldFrom as YieldFromNode; -use PhpParser\Node\Param as ParamNode; use PhpParser\NodeTraverser; -use PhpParser\Parser; use PhpParser\PrettyPrinter\Standard as StandardPrettyPrinter; use PhpParser\PrettyPrinterAbstract; -use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Identifier\Exception\InvalidIdentifierName; -use Roave\BetterReflection\Identifier\Identifier; -use Roave\BetterReflection\Identifier\IdentifierType; use Roave\BetterReflection\Reflection\Annotation\AnnotationHelper; use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper; -use Roave\BetterReflection\Reflection\Exception\InvalidArrowFunctionBodyNode; use Roave\BetterReflection\Reflection\Exception\Uncloneable; -use Roave\BetterReflection\SourceLocator\Ast\Exception\ParseToAstFailure; use Roave\BetterReflection\SourceLocator\Located\LocatedSource; -use Roave\BetterReflection\SourceLocator\Type\ClosureSourceLocator; use Roave\BetterReflection\Util\CalculateReflectionColumn; use Roave\BetterReflection\Util\GetLastDocComment; use Roave\BetterReflection\Util\Visitor\ReturnNodeVisitor; @@ -33,13 +23,9 @@ use function assert; use function count; use function is_array; -use function is_string; -use function strtolower; trait ReflectionFunctionAbstract { - private static ?Parser $parser; - abstract public function __toString(): string; abstract public function getShortName(): string; @@ -334,22 +320,6 @@ private function createReturnType(): ReflectionNamedType|ReflectionUnionType|Ref return ReflectionType::createFromNode($this->reflector, $this, $returnType); } - /** - * Set the return type declaration. - */ - public function setReturnType(string $newReturnType): void - { - $this->node->returnType = new Node\Name($newReturnType); - } - - /** - * Remove the return type declaration completely. - */ - public function removeReturnType(): void - { - $this->node->returnType = null; - } - /** * @throws Uncloneable */ @@ -431,99 +401,6 @@ public function getAttributesByInstance(string $className): array return ReflectionAttributeHelper::filterAttributesByInstance($this->getAttributes(), $className); } - /** - * Override the method or function's body of statements with an entirely new - * body of statements within the reflection. - * - * @throws ParseToAstFailure - * @throws InvalidIdentifierName - * - * @example - * $reflectionFunction->setBodyFromClosure(function () { return true; }); - */ - public function setBodyFromClosure(Closure $newBody): void - { - $closureReflection = (new ClosureSourceLocator($newBody, $this->loadStaticParser()))->locateIdentifier( - $this->reflector, - new Identifier(ReflectionFunction::CLOSURE_NAME, new IdentifierType(IdentifierType::IDENTIFIER_FUNCTION)), - ); - assert($closureReflection instanceof ReflectionFunction); - - $this->setBodyFromAst($closureReflection->getAst()->getStmts()); - } - - /** - * Override the method or function's body of statements with an entirely new - * body of statements within the reflection. - * - * @example - * $reflectionFunction->setBodyFromString('return true;'); - */ - public function setBodyFromString(string $newBody): void - { - /** @var list $stmts */ - $stmts = $this->loadStaticParser()->parse('setBodyFromAst($stmts); - } - - /** - * Override the method or function's body of statements with an entirely new - * body of statements within the reflection. - * - * @param list $nodes - * - * @example - * // $ast should be an array of Nodes - * $reflectionFunction->setBodyFromAst($ast); - */ - public function setBodyFromAst(array $nodes): void - { - // This slightly confusing code simply type-checks the $nodes - // array by unpacking them and splatting them in the closure. - $validator = static fn (Node\Stmt ...$node): array => $node; - $stmts = $validator(...$nodes); - - if ($this->node instanceof Node\Expr\ArrowFunction) { - if (! isset($nodes[0]->expr)) { - throw InvalidArrowFunctionBodyNode::create($nodes[0]); - } - - $this->node->expr = $nodes[0]->expr; - - return; - } - - $this->node->stmts = $stmts; - } - - /** - * Add a new parameter to the method/function. - */ - public function addParameter(string $parameterName): void - { - $this->node->params[] = new ParamNode(new Node\Expr\Variable($parameterName)); - } - - /** - * Remove a parameter from the method/function. - */ - public function removeParameter(string $parameterName): void - { - $lowerName = strtolower($parameterName); - - foreach ($this->node->params as $key => $paramNode) { - $varNode = $paramNode->var; - assert($varNode instanceof Node\Expr\Variable); - - if (! is_string($varNode->name) || strtolower($varNode->name) !== $lowerName) { - continue; - } - - unset($this->node->params[$key]); - } - } - /** * Fetch an array of all return statements found within this function. * @@ -549,9 +426,4 @@ public function getReturnStatementsAst(): array return $visitor->getReturnNodes(); } - - private function loadStaticParser(): Parser - { - return self::$parser ?? self::$parser = (new BetterReflection())->phpParser(); - } } diff --git a/src/Reflection/ReflectionObject.php b/src/Reflection/ReflectionObject.php index 90b051fa6..a5cda80b7 100644 --- a/src/Reflection/ReflectionObject.php +++ b/src/Reflection/ReflectionObject.php @@ -503,32 +503,4 @@ public function getAttributesByInstance(string $className): array { return $this->reflectionClass->getAttributesByInstance($className); } - - public function setFinal(bool $isFinal): void - { - $this->reflectionClass->setFinal($isFinal); - } - - public function removeMethod(string $methodName): bool - { - return $this->reflectionClass->removeMethod($methodName); - } - - public function addMethod(string $methodName): void - { - $this->reflectionClass->addMethod($methodName); - } - - public function removeProperty(string $propertyName): bool - { - return $this->reflectionClass->removeProperty($propertyName); - } - - public function addProperty( - string $propertyName, - int $visibility = CoreReflectionProperty::IS_PUBLIC, - bool $static = false, - ): void { - $this->reflectionClass->addProperty($propertyName, $visibility, $static); - } } diff --git a/src/Reflection/ReflectionParameter.php b/src/Reflection/ReflectionParameter.php index 431c4a774..0916c7274 100644 --- a/src/Reflection/ReflectionParameter.php +++ b/src/Reflection/ReflectionParameter.php @@ -334,22 +334,6 @@ public function hasType(): bool return $this->node->type !== null; } - /** - * Set the parameter type declaration. - */ - public function setType(string $newParameterType): void - { - $this->node->type = new Node\Name($newParameterType); - } - - /** - * Remove the parameter type declaration completely. - */ - public function removeType(): void - { - $this->node->type = null; - } - /** * Is this parameter an array? */ diff --git a/src/Reflection/ReflectionProperty.php b/src/Reflection/ReflectionProperty.php index b65bb5ba3..fd162af89 100644 --- a/src/Reflection/ReflectionProperty.php +++ b/src/Reflection/ReflectionProperty.php @@ -6,11 +6,9 @@ use Closure; use Error; -use InvalidArgumentException; use OutOfBoundsException; use PhpParser\Node; use PhpParser\Node\NullableType; -use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Property as PropertyNode; use ReflectionException; use ReflectionProperty as CoreReflectionProperty; @@ -118,30 +116,6 @@ public static function createFromNode( ); } - /** - * Set the default visibility of this property. Use the core \ReflectionProperty::IS_* values as parameters, e.g.: - * - * @throws InvalidArgumentException - */ - public function setVisibility(int $newVisibility): void - { - $this->node->flags &= ~Class_::MODIFIER_PRIVATE & ~Class_::MODIFIER_PROTECTED & ~Class_::MODIFIER_PUBLIC; - - switch ($newVisibility) { - case CoreReflectionProperty::IS_PRIVATE: - $this->node->flags |= Class_::MODIFIER_PRIVATE; - break; - case CoreReflectionProperty::IS_PROTECTED: - $this->node->flags |= Class_::MODIFIER_PROTECTED; - break; - case CoreReflectionProperty::IS_PUBLIC: - $this->node->flags |= Class_::MODIFIER_PUBLIC; - break; - default: - throw new InvalidArgumentException('Visibility should be \ReflectionProperty::IS_PRIVATE, ::IS_PROTECTED or ::IS_PUBLIC constants'); - } - } - /** * Has the property been declared at compile-time? * @@ -464,22 +438,6 @@ public function hasType(): bool return $this->node->type !== null; } - /** - * Set the property type declaration. - */ - public function setType(string $newPropertyType): void - { - $this->node->type = new Node\Name($newPropertyType); - } - - /** - * Remove the property type declaration completely. - */ - public function removeType(): void - { - $this->node->type = null; - } - /** * @param class-string $className * diff --git a/test/compat/MonkeyPatchFunction.phpt b/test/compat/MonkeyPatchFunction.phpt deleted file mode 100644 index 07f8b427c..000000000 --- a/test/compat/MonkeyPatchFunction.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -Monkey patch a function (must be done before loaded) ---FILE-- -astLocator() -); - -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector($sourceLocator); - -$functionInfo = $reflector->reflectFunction('increment'); - -// Note, when outputting the code, formatting is lost, so the needless parens will not be expected -$functionInfo->setBodyFromString('return ($a + 2);'); - -var_dump($functionInfo->getBodyCode()); - -// Test that the code executes as expected also -eval((new \PhpParser\PrettyPrinter\Standard())->prettyPrint([$functionInfo->getAst()])); -var_dump(increment(5)); - -?> ---EXPECT-- -bool(false) -string(14) "return $a + 2;" -int(7) diff --git a/test/demo/check-demo.sh b/test/demo/check-demo.sh index 3bc17c2ad..d7e4bff9b 100755 --- a/test/demo/check-demo.sh +++ b/test/demo/check-demo.sh @@ -18,6 +18,5 @@ check () { check demo/basic-reflection/example1.php $'stdClass\ninternal' check demo/basic-reflection/example2.php $'Roave\BetterReflection\Reflection\ReflectionClass\nnot internal' check demo/basic-reflection/example3.php $'MyClass\nprivate' -check demo/monkey-patching/index.php $'4' check demo/parsing-whole-directory/example1.php $'success' check demo/parsing-whole-directory/example2.php $'success' diff --git a/test/unit/Reflection/ReflectionClassTest.php b/test/unit/Reflection/ReflectionClassTest.php index b95fbb254..7a89c058b 100644 --- a/test/unit/Reflection/ReflectionClassTest.php +++ b/test/unit/Reflection/ReflectionClassTest.php @@ -1995,112 +1995,6 @@ class Foo {} self::assertSame('Foo', $ast->name->name); } - public function testSetIsFinal(): void - { - $php = 'astLocator)))->reflectClass('Foo'); - - self::assertTrue($reflection->isFinal()); - - $reflection->setFinal(false); - self::assertFalse($reflection->isFinal()); - - $reflection->setFinal(true); - self::assertTrue($reflection->isFinal()); - } - - public function testSetIsFinalThrowsExceptionForInterface(): void - { - $php = 'astLocator)))->reflectClass('Foo'); - - $this->expectException(NotAClassReflection::class); - $reflection->setFinal(true); - } - - public function testRemoveMethod(): void - { - $php = 'astLocator)))->reflectClass('Foo'); - - self::assertTrue($reflection->hasMethod('bar')); - self::assertTrue($reflection->removeMethod('bar')); - - self::assertFalse($reflection->hasMethod('bar')); - self::assertFalse($reflection->removeMethod('bar')); - } - - public function testAddMethod(): void - { - $php = 'astLocator)))->reflectClass('Foo'); - - self::assertFalse($reflection->hasMethod('bar')); - - $reflection->addMethod('bar'); - - self::assertTrue($reflection->hasMethod('bar')); - } - - public function testRemoveProperty(): void - { - $php = 'astLocator)))->reflectClass('Foo'); - - self::assertTrue($reflection->hasProperty('bar')); - self::assertTrue($reflection->removeProperty('bar')); - self::assertFalse($reflection->hasProperty('bar')); - self::assertFalse($reflection->removeProperty('bar')); - } - - public function testAddProperty(): void - { - $php = 'astLocator)))->reflectClass('Foo'); - - self::assertFalse($reflection->hasProperty('bar')); - - $reflection->addProperty('publicBar', CoreReflectionProperty::IS_PUBLIC); - self::assertTrue($reflection->hasProperty('publicBar')); - self::assertTrue($reflection->getProperty('publicBar')->isPublic()); - - $reflection->addProperty('protectedBar', CoreReflectionProperty::IS_PROTECTED); - self::assertTrue($reflection->hasProperty('protectedBar')); - self::assertTrue($reflection->getProperty('protectedBar')->isProtected()); - - $reflection->addProperty('privateBar', CoreReflectionProperty::IS_PRIVATE); - self::assertTrue($reflection->hasProperty('privateBar')); - self::assertTrue($reflection->getProperty('privateBar')->isPrivate()); - - $reflection->addProperty('staticBar', CoreReflectionProperty::IS_PUBLIC, true); - self::assertTrue($reflection->hasProperty('staticBar')); - self::assertTrue($reflection->getProperty('staticBar')->isStatic()); - } - public function testGetConstantsReturnsAllConstantsRegardlessOfVisibility(): void { $php = 'allowsNull()); } - public function testSetReturnType(): void - { - $functionInfo = (new DefaultReflector( - new SingleFileSourceLocator(__DIR__ . '/../Fixture/Php7ReturnTypeDeclarations.php', $this->astLocator), - ))->reflectFunction('returnsString'); - - $functionInfo->setReturnType('int'); - - self::assertSame('int', (string) $functionInfo->getReturnType()); - self::assertStringStartsWith('function returnsString() : int', (new StandardPrettyPrinter())->prettyPrint([$functionInfo->getAst()])); - } - - public function testRemoveReturnType(): void - { - $functionInfo = (new DefaultReflector( - new SingleFileSourceLocator(__DIR__ . '/../Fixture/Php7ReturnTypeDeclarations.php', $this->astLocator), - ))->reflectFunction('returnsString'); - - $functionInfo->removeReturnType(); - - self::assertNull($functionInfo->getReturnType()); - self::assertStringNotContainsString(': string', (new StandardPrettyPrinter())->prettyPrint([$functionInfo->getAst()])); - } - /** * @requires PHP >= 8.1 */ @@ -608,136 +580,6 @@ function foo() {} self::assertSame('foo', $ast->name->name); } - public function testSetBodyFromClosure(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $function->setBodyFromClosure(static function (): void { - echo 'Hello world!'; - }); - - self::assertSame("echo 'Hello world!';", $function->getBodyCode()); - } - - public function testSetBodyFromClosureWithArrowFunction(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $function->setBodyFromClosure(static fn (): string => 'Hello world!'); - - self::assertSame("return 'Hello world!';", $function->getBodyCode()); - } - - public function testSetBodyFromString(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $function->setBodyFromString("echo 'Hello world!';"); - - self::assertSame("echo 'Hello world!';", $function->getBodyCode()); - } - - public function testSetBodyFromStringForArrowFunction(): void - { - $arrowFunction = static fn () => 10; - - $function = ReflectionFunction::createFromClosure($arrowFunction); - - $function->setBodyFromString("'Hello world!';"); - - self::assertSame("'Hello world!'", $function->getBodyCode()); - } - - public function testSetBodyFromAst(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $function->setBodyFromAst([ - new Echo_([ - new String_('Hello world!'), - ]), - ]); - - self::assertSame("echo 'Hello world!';", $function->getBodyCode()); - } - - public function testSetBodyFromAstForArrowFunction(): void - { - $arrowFunction = static fn () => 10; - - $function = ReflectionFunction::createFromClosure($arrowFunction); - - $function->setBodyFromAst([ - new Return_( - new String_('Hello world!'), - ), - ]); - - self::assertSame("'Hello world!'", $function->getBodyCode()); - } - - public function testSetBodyFromAstWithInvalidArgumentsThrowsException(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $this->expectException(TypeError::class); - $function->setBodyFromAst([1]); - } - - public function testSetBodyFromAstForArrowFunctionWithInvalidArgumentsThrowsException(): void - { - $arrowFunction = static fn () => 10; - - $function = ReflectionFunction::createFromClosure($arrowFunction); - - $this->expectException(InvalidArrowFunctionBodyNode::class); - - $function->setBodyFromAst([ - new Echo_([ - new String_('Hello world!'), - ]), - ]); - } - - public function testAddParameter(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $function->addParameter('myNewParam'); - - self::assertStringStartsWith('function foo($myNewParam)', (new StandardPrettyPrinter())->prettyPrint([$function->getAst()])); - } - - public function testRemoveParameter(): void - { - $php = 'astLocator)); - $function = $reflector->reflectFunction('foo'); - - $function->removeParameter('a'); - - self::assertStringStartsWith('function foo($b)', (new StandardPrettyPrinter())->prettyPrint([$function->getAst()])); - } - public function testGetReturnStatementAstReturnsStatements(): void { $php = <<<'PHP' diff --git a/test/unit/Reflection/ReflectionParameterTest.php b/test/unit/Reflection/ReflectionParameterTest.php index 6a67d3184..36d8153e1 100644 --- a/test/unit/Reflection/ReflectionParameterTest.php +++ b/test/unit/Reflection/ReflectionParameterTest.php @@ -9,7 +9,6 @@ use LogicException; use OutOfBoundsException; use PhpParser\Node\Param; -use PhpParser\PrettyPrinter\Standard as StandardPrettyPrinter; use PHPUnit\Framework\TestCase; use Roave\BetterReflection\Reflection\Exception\Uncloneable; use Roave\BetterReflection\Reflection\ReflectionClass; @@ -347,42 +346,6 @@ public function testHasTypeReturnsFalseWithoutType(): void self::assertFalse($method->getParameter('noTypeParam')->hasType()); } - /** - * @runInSeparateProcess - */ - public function testSetType(): void - { - $classInfo = $this->reflector->reflectClass(PhpParameterTypeDeclarations::class); - $methodInfo = $classInfo->getMethod('foo'); - $parameterInfo = $methodInfo->getParameter('intParam'); - - $parameterInfo->setType('string'); - - self::assertSame('string', (string) $parameterInfo->getType()); - self::assertStringStartsWith( - 'public function foo(string $intParam', - (new StandardPrettyPrinter())->prettyPrint([$methodInfo->getAst()]), - ); - } - - /** - * @runInSeparateProcess - */ - public function testRemoveType(): void - { - $classInfo = $this->reflector->reflectClass(PhpParameterTypeDeclarations::class); - $methodInfo = $classInfo->getMethod('foo'); - $parameterInfo = $methodInfo->getParameter('intParam'); - - $parameterInfo->removeType(); - - self::assertNull($parameterInfo->getType()); - self::assertStringStartsWith( - 'public function foo($intParam', - (new StandardPrettyPrinter())->prettyPrint([$methodInfo->getAst()]), - ); - } - public function isCallableProvider(): array { return [ diff --git a/test/unit/Reflection/ReflectionPropertyTest.php b/test/unit/Reflection/ReflectionPropertyTest.php index d3c03c96d..84072df19 100644 --- a/test/unit/Reflection/ReflectionPropertyTest.php +++ b/test/unit/Reflection/ReflectionPropertyTest.php @@ -6,12 +6,10 @@ use ClassWithPropertiesAndTraitProperties; use ExtendedClassWithPropertiesAndTraitProperties; -use InvalidArgumentException; use OutOfBoundsException; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\PropertyProperty; -use PhpParser\PrettyPrinter\Standard as StandardPrettyPrinter; use PHPUnit\Framework\TestCase; use Reflection; use ReflectionProperty as CoreReflectionProperty; @@ -271,48 +269,6 @@ public function testCannotClone(): void clone $publicProp; } - public function testSetVisibility(): void - { - $classInfo = $this->reflector->reflectClass(ExampleClass::class); - $publicProp = $classInfo->getProperty('publicStaticProperty'); - - self::assertFalse($publicProp->isPrivate(), 'Should initially be public, was private'); - self::assertFalse($publicProp->isProtected(), 'Should initially be public, was protected'); - self::assertTrue($publicProp->isPublic(), 'Should initially be public, was not public'); - self::assertTrue($publicProp->isStatic(), 'Should initially be static'); - - $publicProp->setVisibility(CoreReflectionProperty::IS_PRIVATE); - - self::assertTrue($publicProp->isPrivate(), 'After setting private, isPrivate is not set'); - self::assertFalse($publicProp->isProtected(), 'After setting private, protected is now set but should not be'); - self::assertFalse($publicProp->isPublic(), 'After setting private, public is still set but should not be'); - self::assertTrue($publicProp->isStatic(), 'Should still be static after setting private'); - - $publicProp->setVisibility(CoreReflectionProperty::IS_PROTECTED); - - self::assertFalse($publicProp->isPrivate(), 'After setting protected, should no longer be private'); - self::assertTrue($publicProp->isProtected(), 'After setting protected, expect isProtected to be set'); - self::assertFalse($publicProp->isPublic(), 'After setting protected, public is set but should not be'); - self::assertTrue($publicProp->isStatic(), 'Should still be static after setting protected'); - - $publicProp->setVisibility(CoreReflectionProperty::IS_PUBLIC); - - self::assertFalse($publicProp->isPrivate(), 'After setting public, isPrivate should not be set'); - self::assertFalse($publicProp->isProtected(), 'After setting public, isProtected should not be set'); - self::assertTrue($publicProp->isPublic(), 'After setting public, isPublic should be set but was not'); - self::assertTrue($publicProp->isStatic(), 'Should still be static after setting public'); - } - - public function testSetVisibilityThrowsExceptionWithInvalidArgument(): void - { - $classInfo = $this->reflector->reflectClass(ExampleClass::class); - $publicProp = $classInfo->getProperty('publicProperty'); - - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Visibility should be \ReflectionProperty::IS_PRIVATE, ::IS_PROTECTED or ::IS_PUBLIC constants'); - $publicProp->setVisibility(0); - } - /** * @dataProvider startEndLineProvider */ @@ -695,40 +651,6 @@ public function testGetType( self::assertSame($expectedType, (string) $type); } - /** - * @runInSeparateProcess - */ - public function testSetType(): void - { - $classReflection = $this->reflector->reflectClass(Php74PropertyTypeDeclarations::class); - $propertyReflection = $classReflection->getProperty('integerProperty'); - - $propertyReflection->setType('string'); - - self::assertSame('string', (string) $propertyReflection->getType()); - self::assertStringStartsWith( - 'public string $integerProperty', - (new StandardPrettyPrinter())->prettyPrint([$propertyReflection->getAst()]), - ); - } - - /** - * @runInSeparateProcess - */ - public function testRemoveType(): void - { - $classReflection = $this->reflector->reflectClass(Php74PropertyTypeDeclarations::class); - $propertyReflection = $classReflection->getProperty('integerProperty'); - - $propertyReflection->removeType(); - - self::assertNull($propertyReflection->getType()); - self::assertStringStartsWith( - 'public $integerProperty', - (new StandardPrettyPrinter())->prettyPrint([$propertyReflection->getAst()]), - ); - } - public function isInitializedProvider(): array { $object = new InitializedProperties(); From 9ef7342fb5f2a50f6f33678794d88bf403dd76fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Hansl=C3=ADk?= Date: Mon, 6 Dec 2021 17:37:30 +0100 Subject: [PATCH 2/2] usage.md fixes --- docs/usage.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index e62cb821f..d6466d412 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -137,13 +137,14 @@ Here's an example of `MakeLocatorForComposerJsonAndInstalledJson` usage: astLocator(); -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector(new AggregateSourceLocator([ +$reflector = new DefaultReflector(new AggregateSourceLocator([ (new MakeLocatorForComposerJsonAndInstalledJson)('path/to/the/project', $astLocator), new PhpInternalSourceLocator($astLocator, new ReflectionSourceStubber()) ])); @@ -157,13 +158,13 @@ $classes = $reflector->reflectAllClasses(); astLocator(); -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector(new ComposerSourceLocator($classLoader, $astLocator)); +$reflector = new DefaultReflector(new ComposerSourceLocator($classLoader, $astLocator)); $reflectionClass = $reflector->reflectClass('Foo\Bar\MyClass'); echo $reflectionClass->getShortName(); // MyClass @@ -177,11 +178,11 @@ echo $reflectionClass->getNamespaceName(); // Foo\Bar astLocator(); -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector(new SingleFileSourceLocator('path/to/MyApp/MyClass.php', $astLocator)); +$reflector = new DefaultReflector(new SingleFileSourceLocator('path/to/MyApp/MyClass.php', $astLocator)); $reflectionClass = $reflector->reflectClass('MyApp\MyClass'); echo $reflectionClass->getShortName(); // MyClass @@ -195,13 +196,13 @@ echo $reflectionClass->getNamespaceName(); // MyApp astLocator(); -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector(new StringSourceLocator($code, $astLocator)); +$reflector = new DefaultReflector(new StringSourceLocator($code, $astLocator)); $reflectionClass = $reflector->reflectClass('Foo'); echo $reflectionClass->getShortName(); // Foo @@ -213,11 +214,11 @@ echo $reflectionClass->getShortName(); // Foo astLocator(); -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector(new SingleFileSourceLocator('path/to/file.php', $astLocator)); +$reflector = new DefaultReflector(new SingleFileSourceLocator('path/to/file.php', $astLocator)); $classes = $reflector->reflectAllClasses(); ``` @@ -227,12 +228,12 @@ $classes = $reflector->reflectAllClasses(); astLocator(); $directoriesSourceLocator = new DirectoriesSourceLocator(['path/to/directory1'], $astLocator); -$reflector = new \Roave\BetterReflection\Reflector\DefaultReflector($directoriesSourceLocator); +$reflector = new DefaultReflector($directoriesSourceLocator); $classes = $reflector->reflectAllClasses(); ``` @@ -252,7 +253,6 @@ See example in "Reflecting Classes" section on the same subheading.