1

I have the following interface / classes:

class Part {}
class Engine extends Part{}

interface CarsInterface {
    public function selectTimeLine(Part $object);
}

abstract class Car implements CarsInterface {}

class Hybrid extends Car {
    public function selectTimeLine(Engine $object) {}
}

Why can't i use Engine object in the child signature (Hybrid Class) if Engine is sub-class of "Part" (I know its possible in Java...)

What is the proper way to achieve this functionality in PHP? Thx

Danny Valariola
  • 1,118
  • 5
  • 26
  • 41
  • There's a few questions that address this. This one seems the most promising, suggests using instanceof: http://programmers.stackexchange.com/questions/227766/changing-method-signature-for-implementing-classes-in-php Here's one on SO: http://stackoverflow.com/questions/13423494/why-is-overriding-method-parameters-a-violation-of-strict-standards-in-php Your best bet is probably to remove the type from the argument declaration and use `instanceof`. – Daniel B. Aug 03 '16 at 16:53
  • @MontgomeryJean I saw the second answer while looking around...but can you elaborate on "instanceof" can you give an example? – Danny Valariola Aug 03 '16 at 16:59
  • nevermind...saw it. – Danny Valariola Aug 03 '16 at 17:01

2 Answers2

4

Yeah, PHP is sucks. =)

If I'm not mistaken, you need something like:

interface SomeInterface {
}

class Part implements SomeInterface  {}
class Engine extends Part implements SomeInterface{}

interface CarsInterface {
    public function selectTimeLine(SomeInterface $object);
}

abstract class Car implements CarsInterface {}

class Hybrid extends Car {
    public function selectTimeLine(SomeInterface $object) {}
}
Lakremon
  • 787
  • 1
  • 8
  • 26
  • Since `Part` implements `SomeInterface` and `Engine` extends `Part` the `Engine` object will also implement `SomeInterface` see my example and for test case http://ideone.com/6CNdhk. – Will B. Aug 03 '16 at 17:09
1

In short an interface is meant to provide you with those restrictions by setting specific instructions for your objects. This way when checking on the object's capabilities or with instanceof you can always expect to receive what was specified.

There is no "proper" way to achieve what you are wanting to do, but the suggested method is to type-hint with interfaces as opposed to specific class definitions.

This way you can always guarantee the available methods for the provided objects.

interface TimeLineInterface { }

class Part implements TimeLineInterface { }

class Engine extends Part { }

interface CarInterface
{
    public function selectTimeLine(TimeLineInterface $object);
}

abstract class Car implements CarInterface { }

class Hybrid extends Car
{
   public function selectTimeLine(TimeLineInterface $object) { }
}

if you want to force the acceptance of a specific type of object for the object's method you would need to check the object instance like so.

class Hybrid extends Car
{
   public function selectTimeLine(TimeLineInterface $object) 
   {
       if (!$object instanceof Engine) {
            throw new \InvalidArgumentException(__CLASS__ . '::' . __FUNCTION__ . ' expects an instance of Engine. Received ' . get_class($object));
       }
   }
}
Will B.
  • 17,883
  • 4
  • 67
  • 69