2022-11-19 15:54:02 +01:00
|
|
|
<?php
|
|
|
|
namespace {
|
|
|
|
class ReflectionClass implements Reflector {
|
|
|
|
/** @psalm-pure */
|
|
|
|
public function isReadOnly(): bool {}
|
|
|
|
}
|
Refine `ReflectionUnionType` and `ReflectionIntersectionType` for PHP 8.1 and PHP 8.2
* in PHP 8.0, `ReflectionUnionType` is composed on `ReflectionNamedType`s
* in PHP 8.1, `ReflectionIntersectionType` is composed of `ReflectionNamedType`s
* in PHP 8.2, `ReflectionUnionType` is composed of `ReflectionIntersectionType|ReflectionNamedType`s
Slight variations for each PHP version.
As per local testing, this doesn't work yet.
## Local testing setup:
I did some digging to make sure that the stubs work as expected.
Here's what I did to validate this patch locally (since I don't think it can really be fully automated)
## Create a dummy file to verify used symbols
```php
<?php
namespace Testing;
/** @return \ReflectionClass<\stdClass> */
function getAClass(): \ReflectionClass { throw new \Exception('irrelevant'); }
function getAnUnionType(): \ReflectionUnionType { throw new \Exception('irrelevant'); }
function getAnIntersectionType(): \ReflectionIntersectionType { throw new \Exception('irrelevant'); }
// verifying that `getName()` is stubbed in all versions: this should always be a `class-string<\stdClass>`
$name = getAClass()->getName();
// union types should appear starting with PHP 8.0. Starting with PHP 8.2, they allow for intersections.
$unionTypes = getAnUnionType()->getTypes();
// intersection types should appear starting with PHP 8.1
$intersectionTypes = getAnIntersectionType()->getTypes();
$results = [$name, $unionTypes, $intersectionTypes];
/** @psalm-trace $results */ // tracing this will show us the differences between versions
return $results;
```
## Run the script against various `vimeo/psalm` versions
```sh
docker run --rm -ti -v $(pwd):/app -w /app php:7.4 ./psalm --php-version=7.4 --no-cache reflection-test.php | grep Trace
docker run --rm -ti -v $(pwd):/app -w /app php:8.0 ./psalm --php-version=8.0 --no-cache reflection-test.php | grep Trace
docker run --rm -ti -v $(pwd):/app -w /app php:8.1 ./psalm --php-version=8.1 --no-cache reflection-test.php | grep Trace
docker run --rm -ti -v $(pwd):/app -w /app php:8.2.0RC7-cli ./psalm --php-version=8.2 --no-cache reflection-test.php | grep Trace
```
## Evaluate output
```
❯ docker run --rm -ti -v $(pwd):/app -w /app php:7.4 ./psalm --php-version=7.4 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, mixed, mixed} (see https://psalm.dev/224)
❯ docker run --rm -ti -v $(pwd):/app -w /app php:8.0 ./psalm --php-version=8.0 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, non-empty-list<ReflectionNamedType>, mixed} (see https://psalm.dev/224)
❯ docker run --rm -ti -v $(pwd):/app -w /app php:8.1 ./psalm --php-version=8.1 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, non-empty-list<ReflectionNamedType>, non-empty-list<ReflectionNamedType>} (see https://psalm.dev/224)
psalm on feature/#8720-improve-types-and-purity-for-reflection-symbols [!?] via 🐘 v8.1.13 via ❄️ impure (nix-shell) took 4s
❯ docker run --rm -ti -v $(pwd):/app -w /app php:8.2.0RC7-cli ./psalm --php-version=8.2 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, non-empty-list<ReflectionNamedType>, non-empty-list<ReflectionNamedType>} (see https://psalm.dev/224)
```
2022-12-06 18:26:50 +01:00
|
|
|
|
|
|
|
/** @psalm-immutable */
|
|
|
|
class ReflectionUnionType extends ReflectionType {
|
|
|
|
/** @return non-empty-list<ReflectionNamedType|ReflectionIntersectionType> */
|
|
|
|
public function getTypes(): array {}
|
|
|
|
}
|
2023-02-03 19:09:15 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @psalm-immutable
|
|
|
|
*
|
|
|
|
* @template-covariant Start of string|DateTimeInterface
|
|
|
|
* @implements IteratorAggregate<int, DateTimeInterface>
|
|
|
|
*/
|
|
|
|
class DatePeriod implements IteratorAggregate
|
|
|
|
{
|
|
|
|
const EXCLUDE_START_DATE = 1;
|
|
|
|
const INCLUDE_END_DATE = 2;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Start $start
|
|
|
|
* @param (Start is string ? int-mask<self::EXCLUDE_START_DATE, self::INCLUDE_END_DATE> : DateInterval) $interval
|
|
|
|
* @param (Start is string ? never : (DateTimeInterface|positive-int)) $end
|
|
|
|
* @param (Start is string ? never : int-mask<self::EXCLUDE_START_DATE, self::INCLUDE_END_DATE>) $options
|
|
|
|
*/
|
|
|
|
public function __construct($start, $interval = 0, $end = 1, $options = 0) {}
|
|
|
|
|
|
|
|
/** @psalm-return (Start is string ? Iterator<int, DateTime> : Iterator<int, Start>) */
|
|
|
|
public function getIterator(): Iterator {}
|
|
|
|
}
|
2023-03-03 09:25:27 +01:00
|
|
|
|
|
|
|
#[Attribute(Attribute::TARGET_PARAMETER)]
|
|
|
|
final class SensitiveParameter
|
|
|
|
{
|
|
|
|
public function __construct() {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[Attribute(Attribute::TARGET_CLASS)]
|
|
|
|
final class AllowDynamicProperties
|
|
|
|
{
|
|
|
|
public function __construct() {}
|
|
|
|
}
|
2022-11-19 15:54:02 +01:00
|
|
|
}
|