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));
}
}
}