Php type hinting not getting along with interfaces and abstract classes?

I think it’ll be much easier to see the problem in a code example than writing the question in the first place. Here is my php code:

<?php

interface AnInterface
{
        public function method();
}    

class AClass implements AnInterface
{
        public function method()
        {
                echo __METHOD__;
        }
}    

abstract class AnAbstractClass
{
        abstract public function method( AnInterface $Object );
}

class ConcreteClass extends AnAbstractClass
{
        public function method( AClass $Object )
        {
                $Object->method();
        }
}

$Object1 = new ConcreteClass();
$Object2 = new AClass();

$Object1->method( $Object2 );

The above code causes the following error:

Fatal error: Declaration of ConcreteClass::method() must be compatible with that of AnAbstractClass::method()

The problem is that php doesn’t seem to be recognizing the signatures of AnAbstractClass::method and ConcreteClass::method as compatible. Am I doing something wrong? Thanks!

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

php doesn’t seem to be recognizing the signatures of AnAbstractClass::method and ConcreteClass::method as compatible.

PHP is correct, they’re not compatible. By allowing only instances of AClass (or its children) to be passed to ConcreteClass::method, you’re breaking the contract that AnAbstractClass provides: Any of its subclasses must accept AnInterface as an argument to its method().

If your example worked, and I had another class BClass implementing AnInterface, we’d have a situation where according to AnAbstractClass, method() should accept instances of BClass, while according to ConcreteClass, it shouldn’t.

Change your signature for ConcreteClass::method to match that of AnAbstractClass::method.

Solution 2

Here’s an example that shows, why this is not allowed:

<?php
class BClass implements AnInterface { }

function moo(AnAbstractClass $abstract)
{
    $b = new BClass();
    $abstract->method($b);
}

This would be a valid code, but it would fail, if you pass a ConcreteClass to moo, because its method ConcreteClass::method does not allow BClass.

It is complicated, but it is easier to understand, if you see an example.

Solution 3

Does not compute. We had the same discussion yesterday:
Can parameter types be specialized in PHP

All your derived classes must implement the method signatures identically.

This is something that would ideally be checked at runtime. But in PHP the parser does. (To compensate, PHP does not check private/protected attribute access at parsing time, but let that one rather blow up at runtime.)

If you want to enforce a more stringent type, I would advise:

 assert( is_a($Object, "AClass") );

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply