Search code examples
phpabstract-classoverloadingextend

Must declaration of the child class method be compatible with parent class method in PHP?


This code is running fine.

The ParentClass is abstract class. I think I can verify that by

$class = new ReflectionClass('ParentClass');
$methods = $class->getMethods(ReflectionMethod::IS_ABSTRACT);

which shows a couple of methods, one of which is named methodA.

Here comes what really baffled me:

There is a ChildClass and it is a concrete class and implements one of the abstract method methodA. Using

$method = new ReflectionMethod('ChildClass', 'methodA');
var_dump($method->getParameters());

I can verify that there are 3 parameters. Since I know the code is working good. I used the same ReflectionMethod to verify the ParentClass

$method = new ReflectionMethod('ParentClass', 'methodA');
var_dump($method->getParameters());

This output an empty array which indicates none parameters, I suppose.

Why? Sadly, I can't look at the source code of these classes but I have been trying to figure out this without much progress:

So far, I can only do things like this. The code is in PHP5.4. I really can't figure out how to make an abstract method _myFunction without arguments but the concrete child class method with 3 arguments. PHP uses __call to overload but this is more of a extending issue, I suppose.

class A {}

abstract class MyAbstractClass
{   
    //abstract public function _myFunction();// ERROR
    abstract public function _myFunction(A $a, A $b, A $c);
}

class Foobar extends MyAbstractClass
{   
    public function _myFunction(A $a, A $b, A $c = null)
    {   
        echo "abc";
    }
}

$a = new Foobar();
$a->_myFunction(new A(), new A(), new A());
$a->_myFunction(new A(), new A());

//output: abcabc without error

Added:

After writing down the question, it helps me to further my test, I think I know why now. The child method has given all 3 arguments a default value.

class Foobar extends MyAbstractClass
{   
    public function _myFunction(A $a = null, A $b = null, A $c = null)
    {
        echo "abc";
    }
}

This would work.


Solution

  • As per PHP manual:

    When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility.

    Furthermore the signatures of the methods must match, i.e. the type hints and the number of required arguments must be the same.

    So, the parent class has 0 arguments, the child has 2 required ones. That is the problem. But since you changed your code, as you say:

    The child method has given all 3 arguments a default value.

    You reduced the number of required arguments in the child class to 0. So it works now.

    To recapitate. This is wrong:

    abstract class MyAbstractClass
    {   
        abstract public function _myFunction(); // No parameters required
    }
    
    class Foobar extends MyAbstractClass
    {   
        public function _myFunction(A $a, A $b, A $c = null) // Two parameters required
        {   
            echo "abc";
        }
    }
    

    This would also be wrong:

    abstract class MyAbstractClass
    {   
        abstract public function _myFunction(A $a, A $b, A $c); // Three parameters required
    }
    
    class Foobar extends MyAbstractClass
    {   
        public function _myFunction(A $a, A $b) // Two parameters required
        {   
            echo "abc";
        }
    }
    

    This is okay:

    abstract class MyAbstractClass
    {   
        abstract public function _myFunction(); // No parameters required
    }
    
    class Foobar extends MyAbstractClass
    {   
        public function _myFunction(A $a = null, A $b = null, A $c = null) // No parameters required
        {   
            echo "abc";
        }
    }
    

    And this is also okay:

    abstract class MyAbstractClass
    {   
        abstract public function _myFunction(A $a, A $b, A $c);
    }
    
    class Foobar extends MyAbstractClass
    {   
        public function _myFunction(A $a, A $b, A $c = null)
        {   
            echo "abc";
        }
    }