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:
- I can call
$a->getName();
(becauseAnimalInterface
has that in its contract) - I can call
$b->makeFriend($a);
(becauseAnimalDoInterface
has in its contract that I can pass anything that implementsAnimalInterface
)
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
How to Get Page Number on Dompdf PDF When Using "View"
Error 1148 MySQL the Used Command Is Not Allowed with This MySQL Version
Getting a PHP Pdo Connection from a MySQL_Connect()
Merge Two Multidimensional Arrays and Reindex All Subarrays
How Does PHP Compare Strings with Comparison Operators
PHP Web Scraping of JavaScript Generated Contents
Laravel Eloquent - Attach VS Sync
Convert Lat/Longs to X/Y Co-Ordinates
How to Get CSV File to Download on Ie? Works on Firefox
How to Add Namespace to an Attribute with PHP's Simplexml
Interface Implementation: Declaration Must Be Compatible
Php: Strtotime Is Returning False for a Future Date
MySQL Error When Inserting Data Containing Apostrophes (Single Quotes)
Mysqli_Query(): Couldn't Fetch MySQLi Error
Is Is Bad Practice to Use Array_Walk with MySQLi_Real_Escape_String