Skip to content

Doubling properties with no or async hooks #6546

@derrabus

Description

@derrabus

In the light of #6545, I was playing with doubling hooks on (non-virtual) properties and I noticed a limitation I'd like to discuss.

Basically:

  • If the property has no hooks, I cannot define behavior for it on the stub.
  • If the property has a set hook only, I can define behavior for the set hook, but not the get hook (and vice versa).

For example:

final class PropertyHookTest extends TestCase
{
    public function testGetHook(): void
    {
        $someClass = self::createStub(SomeClass::class);
        $someClass->method('$someProperty::get')->willReturn('Hello');

        $this->assertSame('Hello', $someClass->someProperty);
    }

    public function testSetHook(): void
    {
        $someClass = $this->createMock(SomeClass::class);
        $someClass
            ->expects(self::once())
            ->method('$someProperty::set')
            ->willReturnCallback(static function (mixed $value): void {
                self::assertSame('Hello', $value);
            });

        $someClass->someProperty = 'Hello';
    }
}

class SomeClass
{
    public string $someProperty;

    public function __construct()
    {
        $this->someProperty = 'some value';
    }
}

This limitation appears rather arbitrary to me, given that PHP allows you to add hooks to a property in a child class even though the parent class did not define any or only one hook on that property.

In the context of our example, the following declaration is perfectly valid:

class SomeChildClass extends SomeClass
{
    public string $someProperty {
        get => $this->someProperty;
        set => $this->someProperty = $value;
    }
}

In fact, if I change my original test to mock SomeChildClass instead of SomeClass, the test passes.

My questions:

  • Are there technical reasons against allowing mocks to add hooks that the parent class did not have?
  • Would you be open to a PR that allows adding hooks to mocked properties?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions