Skip to content

Add stub to ReflectionObject class#11774

Open
Kenny1911 wants to merge 3 commits into
vimeo:6.xfrom
Kenny1911:reflection-object-stub
Open

Add stub to ReflectionObject class#11774
Kenny1911 wants to merge 3 commits into
vimeo:6.xfrom
Kenny1911:reflection-object-stub

Conversation

@Kenny1911
Copy link
Copy Markdown

Class ReflectionClass supports generic.

https://psalm.dev/r/6f73e8f1c5
https://psalm.dev/r/d91a57ae92

But ReflectionObject, that extends ReflectionClass doesn't it.

https://psalm.dev/r/700c9575b0

I am add stub of ReflectionObject, that supports generic.

@psalm-github-bot
Copy link
Copy Markdown

I found these snippets:

https://psalm.dev/r/6f73e8f1c5
<?php

declare(strict_types=1);

/** @psalm-check-type $refClass = \ReflectionClass<\DateTimeImmutable> */
$refClass = new \ReflectionClass(\DateTimeImmutable::class);
/** @psalm-check-type $obj = \DateTimeImmutable */
$obj = $refClass->newInstanceWithoutConstructor();
Psalm output (using commit d38e042):

No issues!
https://psalm.dev/r/d91a57ae92
<?php

declare(strict_types=1);

/** @psalm-check-type $refClass = \ReflectionClass<\DateTimeImmutable> */
$refClass = new \ReflectionClass(new \DateTimeImmutable());
/** @psalm-check-type $obj = \DateTimeImmutable */
$obj = $refClass->newInstanceWithoutConstructor();
Psalm output (using commit d38e042):

No issues!
https://psalm.dev/r/700c9575b0
<?php

declare(strict_types=1);

$refObject = new \ReflectionObject(new \DateTimeImmutable());
/** @psalm-check-type $obj = \DateTimeImmutable */
$obj = $refObject->newInstanceWithoutConstructor();
Psalm output (using commit d38e042):

ERROR: CheckType - 7:1 - Checked variable $obj = DateTimeImmutable does not match $obj = object

@alies-dev
Copy link
Copy Markdown
Contributor

@Kenny1911

Nice addition! What do you think about adding some tests to tests/ReflectionTest.php to cover the new stub?

  • E.g. to add these yields at the end of providerValidCodeParse():
yield 'ReflectionObject infers generic type from object' => [
    'code' => <<<'PHP'
        <?php
        $r = new ReflectionObject(new stdClass());
        PHP,
    'assertions' => ['$r===' => 'ReflectionObject<stdClass>'],
];
yield 'ReflectionObject::getName returns class-string' => [
    'code' => <<<'PHP'
        <?php
        $r = new ReflectionObject(new stdClass());
        $name = $r->getName();
        PHP,
    'assertions' => ['$name===' => "'stdClass'"],
];
yield 'ReflectionObject extends ReflectionClass' => [
    'code' => <<<'PHP'
        <?php
        function foo(ReflectionClass $r): void {}
        foo(new ReflectionObject(new stdClass()));
        PHP,
];

Add the invalid code provider method:

/**
 * @psalm-mutation-free
 */
#[Override]
public function providerInvalidCodeParse(): iterable
{
    yield 'ReflectionObject rejects string argument' => [
        'code' => <<<'PHP'
            <?php
            /** @psalm-suppress UndefinedClass */
            new ReflectionObject('stdClass');
            PHP,
        'error_message' => 'InvalidArgument',
    ];
}

This covers:

  • Generic type inference from the constructor (ReflectionObject<stdClass>)
  • Inherited getName() returning the correct narrowed class-string
  • Subtype compatibility with ReflectionClass
  • Constructor rejecting string arguments (unlike ReflectionClass)

Fixed according to the official documentation:
https://www.php.net/manual/en/reflectionclass.newinstanceargs.php
- Set default value empty array of $args argument.
- Make return type nullable.
@Kenny1911
Copy link
Copy Markdown
Author

Kenny1911 commented Mar 31, 2026

@alies-dev

I added the tests

@Kenny1911
Copy link
Copy Markdown
Author

I also noticed a discrepancy in the ReflectioClass::newInstanceArgs() method signature.

I was guided by official php documentation: https://www.php.net/manual/en/reflectionclass.newinstanceargs.php

  • Default value of argument $args if empty array.
  • Return type is nullable object.

I was also fixed and tested it.

@Kenny1911
Copy link
Copy Markdown
Author

Hello! Just writing so this PR doesn't get lost.

I'd really like to get this change merged properly. Could you at least briefly let me know:

Are you planning to review it anytime soon?

Or is there something I should fix right now?

I'm totally open to making changes. Thanks for understanding!

@alies-dev
Copy link
Copy Markdown
Contributor

Hey @Kenny1911
Thanks for your patience! Unfortunetly, I don't have permissions to merge PRs here (but you are more than welcome to contribute to https://github.com/psalm/psalm-plugin-laravel 😁), so we need to ask @danog to take an action.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants