Skip to content

Commit

Permalink
Merge pull request #1092: [spiral/core] generate mixed type in a Pr…
Browse files Browse the repository at this point in the history
…oxy class methods parameters
  • Loading branch information
roxblnfk committed Mar 11, 2024
2 parents d5fe851 + e458c40 commit 819a092
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/Core/src/Internal/Proxy/ProxyClassRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public static function renderParameter(\ReflectionParameter $param): string
return \ltrim(
\sprintf(
'%s %s%s%s%s',
$param->hasType() ? self::renderParameterTypes($param->getType(), $param->getDeclaringClass()) : '',
$param->hasType() ? 'mixed' : '',
$param->isPassedByReference() ? '&' : '',
$param->isVariadic() ? '...' : '',
'$' . $param->getName(),
Expand Down
79 changes: 57 additions & 22 deletions src/Core/tests/Internal/Proxy/ProxyClassRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use ArrayAccess;
use Countable;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Spiral\Core\Attribute\Proxy;
use Spiral\Core\Internal\Proxy\ProxyClassRenderer;
Expand Down Expand Up @@ -50,41 +51,40 @@ public static function provideRenderParameter(): iterable

yield [$from(fn($string) => 0), '$string'];
yield [$from(fn($string = '') => 0), '$string = \'\''];
yield [$from(fn(string $string = "\n\\'\"") => 0), "string \$string = '\n\\\\\\'\"'"];
yield [$from(fn(string $string = '123') => 0), 'string $string = \'123\''];
yield [$from(fn(string $string = self::STRING_CONST) => 0), 'string $string = self::STRING_CONST'];
yield [$from(fn(string $string = "\n\\'\"") => 0), "mixed \$string = '\n\\\\\\'\"'"];
yield [$from(fn(string $string = '123') => 0), 'mixed $string = \'123\''];
yield [$from(fn(string $string = self::STRING_CONST) => 0), 'mixed $string = self::STRING_CONST'];
yield [
$from(fn(string $string = ProxyClassRendererTest::STRING_CONST) => 0),
'string $string = \\' . self::class . '::STRING_CONST',
'mixed $string = \\' . self::class . '::STRING_CONST',
];
yield [$from(fn(string|int $string = self::INT_CONST) => 0), 'string|int $string = self::INT_CONST'];
yield [$from(fn(string|int $string = self::INT_CONST) => 0), 'mixed $string = self::INT_CONST'];
yield [$from(fn(mixed $string = 42) => 0), 'mixed $string = 42'];
yield [$from(fn(int $string = 42) => 0), 'int $string = 42'];
yield [$from(fn(float $string = 42) => 0), 'float $string = 42.0'];
yield [$from(fn(?bool $string = false) => 0), '?bool $string = false'];
yield [$from(fn(bool|null $string = true) => 0), '?bool $string = true'];
yield [$from(fn(object $string = null) => 0), '?object $string = NULL'];
yield [$from(fn(iterable $string = null) => 0), '?iterable $string = NULL'];
yield [$from(fn(Countable&ArrayAccess $val) => 0), '\Countable&\ArrayAccess $val'];
yield [$from(fn(string ...$val) => 0), 'string ...$val'];
yield [$from(fn(string|int ...$val) => 0), 'string|int ...$val'];
yield [$from(fn(string|int &$link) => 0), 'string|int &$link'];
yield [$from(self::withSelf(...)), \sprintf('\%s $self = new self()', self::class)];
yield [$from(fn(object $link = new \stdClass()) => 0), 'object $link = new \stdClass()'];
yield [$from(fn(int $string = 42) => 0), 'mixed $string = 42'];
yield [$from(fn(float $string = 42) => 0), 'mixed $string = 42.0'];
yield [$from(fn(?bool $string = false) => 0), 'mixed $string = false'];
yield [$from(fn(bool|null $string = true) => 0), 'mixed $string = true'];
yield [$from(fn(object $string = null) => 0), 'mixed $string = NULL'];
yield [$from(fn(iterable $string = null) => 0), 'mixed $string = NULL'];
yield [$from(fn(Countable&ArrayAccess $val) => 0), 'mixed $val'];
yield [$from(fn(string ...$val) => 0), 'mixed ...$val'];
yield [$from(fn(string|int ...$val) => 0), 'mixed ...$val'];
yield [$from(fn(string|int &$link) => 0), 'mixed &$link'];
yield [$from(self::withSelf(...)), 'mixed $self = new self()'];
yield [$from(fn(object $link = new \stdClass()) => 0), 'mixed $link = new \stdClass()'];
yield [
$from(fn(#[Proxy] float|int|\stdClass|null $string = new \stdClass(1, 2, bar: "\n'zero")) => 0),
"\stdClass|int|float|null \$string = new \stdClass(1, 2, bar: '\n\'zero')",
"mixed \$string = new \stdClass(1, 2, bar: '\n\'zero')",
];
yield [
$from(fn(SimpleEnum $val = SimpleEnum::B) => 0),
\sprintf('\%s $val = \%s::B', SimpleEnum::class, SimpleEnum::class),
\sprintf('mixed $val = \%s::B', SimpleEnum::class),
];
}

/**
* @dataProvider provideRenderParameter
* @covers ::renderParameter
* @covers ::renderParameterTypes
*/
public function testRenderParameter(\ReflectionParameter $param, $expected): void
{
Expand All @@ -98,9 +98,9 @@ public static function provideRenderMethod(): iterable

#[ExpectedAttribute('public function test1(...$variadic)')]
public function test1(...$variadic) {}
#[ExpectedAttribute('public function test2(string|int $string = self::INT_CONST): string|int')]
#[ExpectedAttribute('public function test2(mixed $string = self::INT_CONST): string|int')]
public function test2(string|int $string = self::INT_CONST): string|int {}
#[ExpectedAttribute('public function test3(object $obj = new \stdClass(new \stdClass(), new \stdClass()))')]
#[ExpectedAttribute('public function test3(mixed $obj = new \stdClass(new \stdClass(), new \stdClass()))')]
public function test3(object $obj = new stdClass(new stdClass(), new stdClass())) {}
#[ExpectedAttribute('public function test4(): \\' . ProxyClassRendererTest::class)]
public function test4(): ProxyClassRendererTest {}
Expand Down Expand Up @@ -128,6 +128,41 @@ public function testRenderMethod(\ReflectionMethod $param, $expected): void
self::assertSame($expected, $signature);
}

#[DataProvider('provideRenderParameterTypes')]
public function testRenderParameterTypes(\ReflectionParameter $param, string $expected): void
{
$this->assertSame(
$expected,
ProxyClassRenderer::renderParameterTypes($param->getType(), $param->getDeclaringClass())
);
}

/**
* @psalm-suppress UnusedClosureParam
*/
public static function provideRenderParameterTypes(): iterable
{
$from = static fn(\Closure $closure): \ReflectionParameter => new \ReflectionParameter($closure, 0);

yield [$from(fn(string $string) => 0), 'string'];
yield [$from(fn(string|int $string) => 0), 'string|int'];
yield [$from(fn(mixed $string) => 0), 'mixed'];
yield [$from(fn(int $string) => 0), 'int'];
yield [$from(fn(float $string) => 0), 'float'];
yield [$from(fn(?bool $string) => 0), '?bool'];
yield [$from(fn(bool|null $string) => 0), '?bool'];
yield [$from(fn(object $string) => 0), 'object'];
yield [$from(fn(iterable $string) => 0), 'iterable'];
yield [$from(fn(Countable&ArrayAccess $val) => 0), '\Countable&\ArrayAccess'];
yield [$from(fn(string ...$val) => 0), 'string'];
yield [$from(fn(string|int ...$val) => 0), 'string|int'];
yield [$from(fn(string|int &$link) => 0), 'string|int'];
yield [$from(self::withSelf(...)), '\\' . self::class];
yield [$from(fn(object $link) => 0), 'object'];
yield [$from(fn(#[Proxy] float|int|\stdClass|null $string) => 0), '\stdClass|int|float|null'];
yield [$from(fn(SimpleEnum $val) => 0), '\\' . SimpleEnum::class];
}

private static function withSelf(self $self = new self()): void
{
}
Expand Down
22 changes: 22 additions & 0 deletions src/Core/tests/Scope/ProxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use Spiral\Tests\Core\Scope\Stub\LoggerInterface;
use Spiral\Tests\Core\Scope\Stub\ScopedProxyLoggerCarrier;
use Spiral\Tests\Core\Scope\Stub\ScopedProxyStdClass;
use Spiral\Tests\Core\Scope\Stub\User;
use Spiral\Tests\Core\Scope\Stub\UserInterface;
use WeakReference;

final class ProxyTest extends BaseTestCase
Expand Down Expand Up @@ -273,6 +275,26 @@ public function __destruct()
self::assertFalse($context->destroyed);
}

public function testImplementationWithWiderTypes(): void
{
$root = new Container();
$root->getBinder('http')->bindSingleton(UserInterface::class, static fn () => new User('Foo'));
$proxy = $root->runScope(new Scope(), static fn(#[Proxy] UserInterface $proxy) => $proxy);

$root->runScope(
new Scope('http'),
static function () use ($root, $proxy) {
self::assertSame('Foo', $proxy->getName());
$proxy->setName(new class implements \Stringable {
public function __toString(): string
{
return 'Bar';
}
});
self::assertSame('Bar', $proxy->getName());
}
);
}

/*
// Proxy::$attachContainer=true tests
Expand Down
23 changes: 23 additions & 0 deletions src/Core/tests/Scope/Stub/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Core\Scope\Stub;

final class User implements UserInterface
{
public function __construct(
private string $name,
) {
}

public function setName(string|\Stringable $name): void
{
$this->name = (string) $name;
}

public function getName(): string
{
return $this->name;
}
}
12 changes: 12 additions & 0 deletions src/Core/tests/Scope/Stub/UserInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Core\Scope\Stub;

interface UserInterface
{
public function setName(string $name): void;

public function getName(): string;
}

0 comments on commit 819a092

Please sign in to comment.