-
-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add PHP 8.0+ Union and Intersection type support on SelfValueVisitor
- Loading branch information
1 parent
452a023
commit 9f33694
Showing
4 changed files
with
357 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
tests/Go/Instrument/Transformer/_files/php80-file-transformed.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
<?php | ||
/** | ||
* Parser Reflection API | ||
* | ||
* @copyright Copyright 2016, Lisachenko Alexander <[email protected]> | ||
* | ||
* This source file is subject to the license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Go\ParserReflection\Stub; | ||
|
||
use Attribute; | ||
use Go\ParserReflection\{ReflectionMethod, ReflectionProperty as P}; | ||
|
||
class ClassWithPhp80Features | ||
{ | ||
public function acceptsStringArrayDefaultToNull(array|string $iterable = null) : array {} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/named-parameters | ||
*/ | ||
class ClassWithPHP80NamedCall | ||
{ | ||
public static function foo(string $key1 = '', string $key2 = ''): string | ||
{ | ||
return $key1 . ':' . $key2; | ||
} | ||
|
||
public static function namedCall(): array | ||
{ | ||
return [ | ||
'key1' => \Go\ParserReflection\Stub\ClassWithPHP80NamedCall::foo(key1: 'bar'), | ||
'key2' => \Go\ParserReflection\Stub\ClassWithPHP80NamedCall::foo(key2: 'baz'), | ||
'keys' => \Go\ParserReflection\Stub\ClassWithPHP80NamedCall::foo(key1: 'A', key2: 'B'), | ||
'reverseKeys' => \Go\ParserReflection\Stub\ClassWithPHP80NamedCall::foo(key2: 'A', key1: 'B'), | ||
'unpack' => \Go\ParserReflection\Stub\ClassWithPHP80NamedCall::foo(...['key1' => 'C', 'key2' => 'D']), | ||
]; | ||
} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/attributes | ||
*/ | ||
#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)] | ||
readonly class ClassPHP80Attribute | ||
{ | ||
private string $value; | ||
|
||
public function __construct(string $value) | ||
{ | ||
$this->value = $value; | ||
} | ||
|
||
public function getValue(): string | ||
{ | ||
return $this->value; | ||
} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/attributes | ||
*/ | ||
#[ClassPHP80Attribute('class')] | ||
class ClassPHP80WithAttribute | ||
{ | ||
#[ClassPHP80Attribute('first')] | ||
#[ClassPHP80Attribute('second')] | ||
public const PUBLIC_CONST = 1; | ||
|
||
#[ClassPHP80Attribute('property')] | ||
private string $privateProperty = 'foo'; | ||
|
||
#[ClassPHP80Attribute('method')] | ||
public function bar(#[ClassPHP80Attribute('parameter')] $parameter) | ||
{} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/constructor-property-promotion | ||
*/ | ||
class ClassPHP80WithPropertyPromotion | ||
{ | ||
public function __construct( | ||
private string $privateStringValue, | ||
private $privateNonTypedValue, | ||
protected int $protectedIntValue = 42, | ||
public array $publicArrayValue = [M_PI, M_E], | ||
) {} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/union-types | ||
*/ | ||
class ClassWithPHP80UnionTypes | ||
{ | ||
public string|int|float|bool $scalarValue; | ||
|
||
public array|object|null $complexValueOrNull = null; | ||
|
||
/** | ||
* Special case, internally iterable should be replaced with Traversable|array | ||
*/ | ||
public iterable|object $iterableOrObject; | ||
|
||
public static function returnsUnionType(): object|array|null {} | ||
|
||
public static function acceptsUnionType(\stdClass|\Traversable|array $iterable): void {} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/mixed-type | ||
*/ | ||
class ClassWithPHP80MixedType | ||
{ | ||
public mixed $someMixedPublicProperty; | ||
|
||
public static function returnsMixed(): mixed {} | ||
|
||
public static function acceptsMixed(mixed $value): void {} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.0/static-return-type | ||
*/ | ||
class ClassWithPHP80StaticReturnType | ||
{ | ||
public static function create(): static {} | ||
} |
119 changes: 119 additions & 0 deletions
119
tests/Go/Instrument/Transformer/_files/php81-file-transformed.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
<?php | ||
/** | ||
* Parser Reflection API | ||
* | ||
* @copyright Copyright 2024, Lisachenko Alexander <[email protected]> | ||
* | ||
* This source file is subject to the license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Go\ParserReflection\Stub; | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/readonly | ||
*/ | ||
class ClassWithPhp81ReadOnlyProperties | ||
{ | ||
public readonly int $publicReadonlyInt; | ||
|
||
protected readonly array $protectedReadonlyArray; | ||
|
||
private readonly object $privateReadonlyObject; | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/enums | ||
*/ | ||
enum SimplePhp81EnumWithSuit { | ||
case Clubs; | ||
case Diamonds; | ||
case Hearts; | ||
case Spades; | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/enums#enums-backed | ||
*/ | ||
enum BackedPhp81EnumHTTPMethods: string | ||
{ | ||
case GET = 'get'; | ||
case POST = 'post'; | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/enums#enum-methods | ||
*/ | ||
enum BackedPhp81EnumHTTPStatusWithMethod: int | ||
{ | ||
case OK = 200; | ||
case ACCESS_DENIED = 403; | ||
case NOT_FOUND = 404; | ||
|
||
public function label(): string { | ||
return static::getLabel($this); | ||
} | ||
|
||
public static function getLabel(\Go\ParserReflection\Stub\ClassWithPhp81ReadOnlyProperties $value): string { | ||
return match ($value) { | ||
\Go\ParserReflection\Stub\ClassWithPhp81ReadOnlyProperties::OK => 'OK', | ||
\Go\ParserReflection\Stub\ClassWithPhp81ReadOnlyProperties::ACCESS_DENIED => 'Access Denied', | ||
\Go\ParserReflection\Stub\ClassWithPhp81ReadOnlyProperties::NOT_FOUND => 'Page Not Found', | ||
}; | ||
} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/intersection-types | ||
*/ | ||
class ClassWithPhp81IntersectionType implements \Countable | ||
{ | ||
private \Iterator&\Countable $countableIterator; | ||
|
||
public function __construct(\Iterator&\Countable $countableIterator) | ||
{ | ||
$this->countableIterator = $countableIterator; | ||
} | ||
|
||
public function count(): int | ||
{ | ||
return count($this->countableIterator); | ||
} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/intersection-types | ||
*/ | ||
function functionWithPhp81IntersectionType(\Iterator&\Countable $value): \Iterator&\Countable { | ||
foreach($value as $val) {} | ||
count($value); | ||
|
||
return $value; | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/never-return-type | ||
*/ | ||
class ClassWithPhp81NeverReturnType | ||
{ | ||
public static function doThis(): never | ||
{ | ||
throw new \RuntimeException('Not implemented'); | ||
} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/never-return-type | ||
*/ | ||
function functionWithPhp81NeverReturnType(): never | ||
{ | ||
throw new \RuntimeException('Not implemented'); | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.1/final-class-const | ||
*/ | ||
class ClassWithPhp81FinalClassConst { | ||
final public const TEST = '1'; | ||
} |
94 changes: 94 additions & 0 deletions
94
tests/Go/Instrument/Transformer/_files/php82-file-transformed.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
<?php | ||
/** | ||
* Parser Reflection API | ||
* | ||
* @copyright Copyright 2016, Lisachenko Alexander <[email protected]> | ||
* | ||
* This source file is subject to the license that is bundled | ||
* with this source code in the file LICENSE. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Go\ParserReflection\Stub; | ||
|
||
/** | ||
* @see https://php.watch/versions/8.2/readonly-classes | ||
*/ | ||
readonly class ClassWithPhp82ReadOnlyFlag | ||
{ | ||
public int $publicInt; | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.2/dnf-types | ||
*/ | ||
class ClassWithPhp82DNFType | ||
{ | ||
private (JSONResponse&SuccessResponse)|HTMLResponse|string $respond; | ||
|
||
public function __construct((JSONResponse&SuccessResponse)|HTMLResponse|string $respond) | ||
{ | ||
$this->respond = $respond; | ||
} | ||
|
||
public function respond(): (JSONResponse&SuccessResponse)|HTMLResponse|string | ||
{ | ||
return $this->respond; | ||
} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.2/null-false-types | ||
* @see https://php.watch/versions/8.2/true-type | ||
*/ | ||
class ClassWithPhp82NullFalseTypes | ||
{ | ||
private true $isTrue = true; | ||
private false $isFalse = false; | ||
private null $isNull = null; | ||
|
||
public function returnsFalse(): false | ||
{ | ||
return false; | ||
} | ||
|
||
public function returnsTrue(): true | ||
{ | ||
return true; | ||
} | ||
|
||
public function returnsNullExplicitly(): null | ||
{ | ||
return null; | ||
} | ||
|
||
public function acceptsTrue(true $acceptsTrue): void {} | ||
public function acceptsFalse(false $acceptsFalse): void {} | ||
public function acceptsNull(null $acceptsNull): void {} | ||
} | ||
|
||
/** | ||
* @see https://php.watch/versions/8.2/constants-in-traits | ||
*/ | ||
trait TraitWithPhp82Constant | ||
{ | ||
protected const CURRENT_VERSION = '2.6'; | ||
final protected const MIN_VERSION = '2.5'; | ||
|
||
protected function ensureVersion(): void | ||
{ | ||
if (\Go\ParserReflection\Stub\ClassWithPhp82NullFalseTypes::CURRENT_VERSION < \Go\ParserReflection\Stub\ClassWithPhp82NullFalseTypes::MIN_VERSION) { | ||
throw new \Exception('Current version is too old'); | ||
} | ||
} | ||
} | ||
|
||
class ClassWithPhp82SensitiveAttribute | ||
{ | ||
private string $secret; | ||
|
||
public function __construct(#[\SensitiveParameter] string $secret = 'password') | ||
{ | ||
$this->secret = $secret; | ||
} | ||
} |