Interface Implementation: Declaration Must Be Compatible

Interface implementation: declaration must be compatible

No, an interface must be implemented exactly. If you restrict the implementation to a more specific subclass, it's not the same interface/signature. PHP doesn't have generics or similar mechanisms.

You can always manually check in code, of course:

if (!($object instanceof Product)) {
throw new InvalidArgumentException;
}

Fatal error: Declaration of .. must be compatible with .. PHP (parameter required: extended class of specification)

The issue may to be that in the abstract class declaration, I am specifying that any LangPrefSet must be acceptable to the reconcile() object method:

abstract public function reconcile(LangPrefSet $other);

— Whereas in the actual method declaration, I am specifying in one case that only a LangPrefSet_Resource would be acceptable, and in the other case, that only a LangPrefSet_For_User would be acceptable.

The object method declarations are therefore incompatible with the abstract method declaration. It seems that the proper application of these interface/abstract method declaration techniques is not to broaden the range of permissible parameter type constraints in classes that implement the interface, since we may achieve this simply by declaring the input restrictions as they ought to be for those specific classes/methods; but rather, interface/abstract method declarations are meant to broaden the range of parameters that may actually be passed to a method that specifies these abstract parameter types.

method must be compatible with interface method

interface Process
{
public function charge($customerProfileId, $paymentProfileId);
// Other items
}

abstract class CardProcessor implements Process
{
// Some methods & properties are here
public abstract function charge($customerProfileId, $paymentProfileId);
}

class Authorize extends CardProcessor
{
public function charge($customerProfileId, $paymentProfileId = null)
{
// Process the card on profile
}
}
  • Added method signature to abstract class CardProcessor as suggested by @Dev Mode
  • Took implementation
    out of interface ( var = null ) and put it in the concrete class.

Declaration of class must be compatible with interface

The self type in your interface refers to the interface - in your class it refers to the class. Those are two different types. You need to use the interface type name when defining the method in order for the types to match. When implementing an interface method, the signature, including the types, has to match for the implementation to be picked up.

public function compara(Comparare $a) {

PHP OOP Declaration of interface implementation compatibility

An interface's only job is to enforce the fact that two objects behave in an identical way, regardless of how they implement that behaviour. It is a contract stating that two objects are interchangeable for certain specific purposes.

(Edit: This part of the code has been corrected, but serves as a good introduction.) The interface AnimalInterface defines the behaviour (function) getAnimalName(), and any class claiming to implement that interface must implement that behaviour. class Dog is declared with implements AnimalInterface, but doesn't implement the required behaviour - you can't call getAnimalName() on instances of Dog. So we already have a fatal error, as we have not met the "contract" defined by the interface.

Fixing that and proceeding, you then have an interface AnimalDoInterface which has the defined behaviour (function) of makeFriend(AnimalInterface $animal) - meaning, you can pass any object which implements AnimalInterface to the makeFriend method of any object which implements AnimalDoInterface.

But you then define class DogFriend with a more restrictive behaviour - its version of makeFriend can only accept Dog objects; according to the interface it should also be able to accept Cat objects, which also implement AnimalInterface, so again, the "contract" of the interface is not met, and we will get a fatal error.

If we were to fix that, there is a different problem in your example: you have a call to $cat->hateFriends(); but if your argument was of type AnimalInterface or AnimalDoInterface, you would have no way to know that a hateFriends() function existed. PHP, being quite relaxed about such things, will let you try that and blow up at runtime if it turns out not to exist after all; stricter languages would only let you use functions that are guaranteed to exist, because they are declared in the interface.


To understand why you can't be more restrictive than the interface, imagine you don't know the class of a particular object, all you know is that it implements a particular interface.

If I know that object $a implements AnimalInterface, and object $b implements AnimalDoInterface, I can make the following assumptions, just by looking at the interfaces:

  1. I can call $a->getName(); (because AnimalInterface has that in its contract)
  2. I can call $b->makeFriend($a); (because AnimalDoInterface has in its contract that I can pass anything that implements AnimalInterface)

But with your code, if $a was a Cat, and $b was a DogFriend, my assumption #2 would fail. If the interface let this happen, it wouldn't be doing its job.

Declaration of method must be compatible with that of interface method - when method signatures are exactly the same?

Seems seconds after posting the question my brain switched on:

It was the fact that I was using a namespace in the interface, so (Venue $venue) was actually (Repository\Venue $venue). Simply changing this:

public static function allInVenue(Venue $venue);

public static function findByIdInVenue(Venue $venue);

To this

public static function allInVenue(\Venue $venue);

public static function findByIdInVenue(\Venue $venue);

Solved the issue. Keeping this up in case anyone else stumbles across the same mistake, to avoid headaches

Fatal error: Declaration of .. must be compatible with .. PHP

Ishoppingcart::addToCart() states that the method does not take any parameter, while the implementation Shoppingcart::addToCart(Product $product) requires that a parameter of type Product must be passed into the method. This means that both declarations are incompatible and while the implemented interface must be satisfied PHP throws the shown error.

Solution would be to either change Ishoppingcart::addToCart() to Ishoppingcart::addToCart(Product $product) so that it requires a parameter of type Product or to change Shoppingcart::addToCart(Product $product) to allow no parameter to passed into the method: Shoppingcart::addToCart(Product $product = null);

The correct way depends on your application requirements.

PHP OOP Implementation must be compatible

Imagine you have a class B which also extends AC. Then I requires that any of its implementations also accept B as argument to method. Your InterfaceImplementation, however, doesn't.

The bigger picture: You might want to reconsider your design if you need to specify a concrete type in the implementation. The idea is that to the outside world, all that needs to be known is encoded by AC and there should not be an InterfaceImplementation that ever needs to know which concrete subclass is being transferred. Maybe the specific stuff can be embedded in C's code and generically called through a method exposed by AC?

Yet another update: You might be able to achieve what you want using generics, but I don't think they exist in PHP. I still think if you share the details of the design problem that might make another interesting question :)

Declaration not compatible with interface (PHP)

Consider this:

class NotBicycle implements Vehicle { ... }

interface VehicleInterface {
public function create(Vehicle $vehicle);
}

class BicycleService implements VehicleInterface {
public function create(Bicycle $bicycle) {
$bicycle->setManufacturer('Some company'); // Common for all Vehicle objects
$bicycle->addSaddle(); // Common only for Bicycle objects
}
}

function createVehicle(VehicleInterface $service, Vehicle $vehicle) {
$service->create($vehicle);
}
$service = new BicycleService();
$vehicle = new NotBicycle();
createVehicle($service, $vehicle);

Even if you were somehow able to only accept a Bicycle in the BicycleService, createVehicle($service, $vehicle) will still work because VehicleInterface has a method create(Vehicle $vehicle). Therefore in order to get this to work the way you want it, you need to basically break what an interface is.

Your only real option is to add a runtime type check. Like e.g.

class BicycleService implements VehicleInterface {
public function create(Vehicle $bicycle) {
if (!$bicycle instance of Bicycle) {
throw new TypeError('Expected Bicycle but got '.get_class($bicycle));
}
$bicycle->setManufacturer('Some company'); // Common for all Vehicle objects
$bicycle->addSaddle(); // Common only for Bicycle objects
}
}

What you are trying to do is called a covariant method parameter type and is not allowed in most object-oriented programming languages because it breaks the Liskov substitution principle

Read more on parameter covariance and contravariance



Related Topics



Leave a reply



Submit