1

So I have 4 classes

class BaseConstraints {}

class ChildConstraints extends BaseConstraints {}

class BaseClass {
  function someMethod(BaseConstraints $baseConstraints) {}
}

class ChildClass extends BaseClass {
  function someMethod(ChildConstraints $childConstraints) {
    parent::someMethod($childConstraints)
  }
}

When running under PHP 7 everything was great. Having upgraded to PHP 8.1, I'm getting the error Declaration of ChildClass::someMethod(ChildConstraints $childConstraints) must be compatible with BaseClass::someMethod(BaseConstraints $bConstraints)

Given that the child classes extend the base classes, I'm not entirely too sure why that would be having that issue. In PHP 7, if I run the following

$a = new ChildClass();
echo var_export(is_a($a, 'BaseClass'), true);

$b = new ChildConstraints();
echo var_export(is_a($b, 'BaseConstraints'), true);

both print out true. So why does PHP 8 complain about the incompatibility if ChildConstraints is a BaseConstraints? Beyond that, though, how can I address this situation? We have cases like the above all throughout our codebase -- hundreds, if not thousands, of them -- so I'm worried about potential solutions. Off the top of my head, I can think of 3 routes to take:

  1. have all the child classes, when type-hinting a child method overriding the parent, revert to using the base class everywhere. I don't really like that because there could be complaints accessing methods evident only in the child class.

  2. use interfaces. I tried that just to see for BaseConstraints and PHP didn't throw a fatal. But using this solution, I would have to create an interface that both the base class and all of its child classes implement. Then change all the signatures to use the interface.

  3. stop type-hinting where derived classes are utilized

None of those seem ideal. Is there something else I can do?

thnx,
Christoph

Christoph
  • 978
  • 7
  • 17
  • [Covariance and Contravariance](https://www.php.net/manual/en/language.oop5.variance.php) – Rain Oct 02 '22 at 00:52
  • Thank you for your reply. So what's the best practice for this? All child classes always use the more generic type (e.g.,, Food) and shouldn't ever be more specific to that child class' needs (e.g., CatFood)? Even when the child class' overridden method expects behavior provided by a derived type (e.g., CatFood)? – Christoph Oct 03 '22 at 12:50

0 Answers0