Skip to content

Commit

Permalink
Merge pull request #490 from daniel-sc/fix-class-without-namespace
Browse files Browse the repository at this point in the history
fix: prevent generating "namespace ;" for classes without declared namespace
  • Loading branch information
lisachenko authored Feb 7, 2024
2 parents 2801484 + 45e6c61 commit 45c19c9
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 5 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
"Go\\Tests\\TestProject\\": "tests/Fixtures/project/src/"
},
"files": [
"tests/functions.php"
"tests/functions.php",
"tests/Go/Stubs/ClassWithoutNamespace.php"
]
},

Expand Down
2 changes: 1 addition & 1 deletion src/Aop/Framework/AbstractInterceptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ abstract class AbstractInterceptor implements Interceptor, OrderedAdvice, Serial
/**
* Advice order
*/
private int $adviceOrder;
private int $adviceOrder = 0;

/**
* Default constructor for interceptor
Expand Down
2 changes: 1 addition & 1 deletion src/Aop/Framework/AbstractMethodInvocation.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ abstract class AbstractMethodInvocation extends AbstractInvocation implements Me
/**
* Instance of object for invoking
*/
protected ?object $instance;
protected ?object $instance = null;

/**
* Instance of reflection method for invocation
Expand Down
2 changes: 1 addition & 1 deletion src/Instrument/Transformer/SelfValueVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function beforeTraverse(array $nodes)
public function enterNode(Node $node)
{
if ($node instanceof Namespace_) {
$this->namespace = $node->name->toString();
$this->namespace = !empty($node->name) ? $node->name->toString() : null;
} elseif ($node instanceof Class_) {
if ($node->name !== null) {
$this->className = new Name($node->name->toString());
Expand Down
2 changes: 1 addition & 1 deletion src/Proxy/ClassProxyGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public function __construct(

$this->generator = new ClassGenerator(
$originalClass->getShortName(),
$originalClass->getNamespaceName(),
!empty($originalClass->getNamespaceName()) ? $originalClass->getNamespaceName() : null,
$originalClass->isFinal() ? ClassGenerator::FLAG_FINAL : null,
$parentClassName,
$introducedInterfaces,
Expand Down
37 changes: 37 additions & 0 deletions tests/Go/Aop/Framework/AbstractMethodInvocationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,41 @@ public function testProvidesAccessToAnnotations(): void
{
$this->assertInstanceOf(AnnotationAccess::class, $this->invocation->getMethod());
}

public function testInstanceIsInitialized(): void
{
$this->expectNotToPerformAssertions();
$o = new class extends AbstractMethodInvocation {

protected static string $propertyName = 'scope';
public function __construct()
{
parent::__construct([new AroundInterceptor(function () {})], '\Go\Aop\Framework\AbstractMethodInvocationTest', 'testInstanceIsInitialized');
}

public function isDynamic(): bool
{
return false;
}

public function getThis(): ?object
{
return null;
}

public function getScope(): string
{
return 'testScope';
}

public function proceed()
{
if ($this->level < 3) {
$this->__invoke('testInstance');
}
}
};

$o->__invoke('testInstance');
}
}
10 changes: 10 additions & 0 deletions tests/Go/Instrument/Transformer/SelfValueTransformerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,14 @@ public function testTransformerReplacesAllSelfPlaces(): void
$expected = file_get_contents(__DIR__ . '/_files/file-with-self-transformed.php');
$this->assertSame($expected, (string) $metadata->source);
}

public function testTransformerReplacesAllSelfPlacesWithoutNamespace(): void
{
$testFile = fopen(__DIR__ . '/_files/file-with-self-no-namespace.php', 'rb');
$content = stream_get_contents($testFile);
$metadata = new StreamMetaData($testFile, $content);
$this->transformer->transform($metadata);
$expected = file_get_contents(__DIR__ . '/_files/file-with-self-no-namespace-transformed.php');
$this->assertSame($expected, (string) $metadata->source);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/** @noinspection PhpIllegalPsrClassPathInspection */
declare(strict_types=1);

class ClassWithSelfNoNamespace extends \Exception
{
const CLASS_CONST = \ClassWithSelfNoNamespace::class;

private static $foo = 42;

private \ClassWithSelfNoNamespace $instance;

public function acceptsAndReturnsSelf(\ClassWithSelfNoNamespace $instance): \ClassWithSelfNoNamespace
{
return $instance;
}

public function containsClosureWithSelf()
{
$func = function (\ClassWithSelfNoNamespace $instance): \ClassWithSelfNoNamespace {
return $instance;
};
$func($this);
}

public function staticMethodCall()
{
return \ClassWithSelfNoNamespace::staticPropertyAccess();
}

public function classConstantFetch()
{
return \ClassWithSelfNoNamespace::class . \ClassWithSelfNoNamespace::CLASS_CONST;
}

public static function staticPropertyAccess()
{
return self::$foo;
}

public function newInstanceCreation()
{
return new \ClassWithSelfNoNamespace;
}

public function catchSection()
{
try {
throw new \ClassWithSelfNoNamespace;
} catch (\ClassWithSelfNoNamespace $exception) {
// Nop
}
}

public function instanceCheck()
{
if ($this instanceof \ClassWithSelfNoNamespace) {
// Nop
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/** @noinspection PhpIllegalPsrClassPathInspection */
declare(strict_types=1);

class ClassWithSelfNoNamespace extends \Exception
{
const CLASS_CONST = self::class;

private static $foo = 42;

private self $instance;

public function acceptsAndReturnsSelf(self $instance): self
{
return $instance;
}

public function containsClosureWithSelf()
{
$func = function (self $instance): self {
return $instance;
};
$func($this);
}

public function staticMethodCall()
{
return self::staticPropertyAccess();
}

public function classConstantFetch()
{
return self::class . self::CLASS_CONST;
}

public static function staticPropertyAccess()
{
return self::$foo;
}

public function newInstanceCreation()
{
return new self;
}

public function catchSection()
{
try {
throw new self;
} catch (self $exception) {
// Nop
}
}

public function instanceCheck()
{
if ($this instanceof self) {
// Nop
}
}
}
1 change: 1 addition & 0 deletions tests/Go/Proxy/ClassProxyGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public function dataGenerator(): array
[First::class, 'publicMethod'],
[First::class, 'protectedMethod'],
[First::class, 'passByReference'],
[\ClassWithoutNamespace::class, 'publicMethod'],
];
}
}
11 changes: 11 additions & 0 deletions tests/Go/Stubs/ClassWithoutNamespace.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php /** @noinspection PhpIllegalPsrClassPathInspection */


class ClassWithoutNamespace
{
public function publicMethod(): int
{
return 1;
}

}

0 comments on commit 45c19c9

Please sign in to comment.