Repository navigation
Properties (hooks) and inheritance #15424
Copy link
Copy link
Open
Description
Description
Referenced RFC #13455
The following code:
<?php
interface ExampleInterface {} // parent
interface MutableExampleInterface extends ExampleInterface {} // child
final class Example implements MutableExampleInterface {} // impl
// parent provider
interface ExampleProviderInterface
{
// Any type that implements ExampleInterface can be read
public ExampleInterface $property { get; }
}
// child provider that "overrides" parent definition
interface MutableExampleProviderInterface extends ExampleProviderInterface
{
// Any type that implements (MutableExampleInterface & ExampleInterface) can be read + write
// We supplement the object with the set method
public MutableExampleInterface $property { get; set; }
}
// An implementation that uses implementation
final class ExampleProvider implements MutableExampleProviderInterface
{
public Example $property { // << implementation
// We can return the implementation, because it implements (MutableExampleInterface & ExampleInterface)
get => $this->property;
// Any instance of ExampleInterface is allowed for set, since it satisfies the covariance condition
set (ExampleInterface $v) => $this->property = new Example($v);
}
}Resulted in this output:
Fatal error: Type of ExampleProvider::$property must be MutableExampleInterface (as in class MutableExampleProviderInterface)
But I expected this output instead:
*nothing*
Same code (logic) using getters and setters instead of properties: https://onlinephp.io/c/4e180
interface ExampleInterface {}
interface MutableExampleInterface extends ExampleInterface {}
final class Example implements MutableExampleInterface {}
interface ExampleProviderInterface
{
public function getProperty(): ExampleInterface;
}
interface MutableExampleProviderInterface extends ExampleProviderInterface
{
public function getProperty(): MutableExampleInterface;
public function setProperty(MutableExampleInterface $value): void;
}
final class ExampleProvider implements MutableExampleProviderInterface
{
public function getProperty(): Example {}
public function setProperty(ExampleInterface $value): void {}
}Ping @iluuu1994 (again) ^_^
PHP Version
PHP 8.4-beta1
Operating System
No response
Reacted by Valentin Udaltsov and Kirill Nesmeyanov
Activity
iluuu1994 commentedon Aug 16, 2024
This is not really a bug but a feature request. We specifically considered this case but decided not to further complicate LSP rules. This may be considered in the future.
SerafimArts commentedon Aug 16, 2024
kk. Should I close this issue in that case?
iluuu1994 commentedon Aug 16, 2024
It's ok, it can remain as a feature request. Thanks for the report.
vudaltsov commentedon Aug 27, 2024
By the way,
readonlyproperties could also become covariant. Initially Nikita stated in his RFC, that readonly properties cannot be covariant due to possible initialization from a different class in the hierarchy. But now readonly properties can only be initialized from the declaring class, so covariance can be enabled for them as well.iluuu1994 commentedon Aug 27, 2024
From the RFC:
This hasn't really changed. both
AandBcan write to the property. I thinkreadonlywith inheritance is inherently risky, given that changes to the parent can break the write in the child, or vice versa. The narrowing of the child type is only sound if the child can guarantee the parent doesn't attempt to write to it.vudaltsov commentedon Aug 28, 2024
Oh, yes, my bad. I was testing it like this https://3v4l.org/XFLc4 instead of https://3v4l.org/bafTR.