Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are the method declarations not compatible?

Why do I receive this error:

Fatal error: Declaration of ConcreteFooMapper::load() must be compatible with that of AbstractFooMapper::load() on line 18

from this code:

<?php
interface Foo {
    public function foo();
}

class ConcreteFoo implements Foo {
    public function foo() {

    }
}

abstract class AbstractFooMapper {
    abstract public function load(Foo $entity, array $data);
}

class ConcreteFooMapper extends AbstractFooMapper {
    public function load(ConcreteFoo $entity, array $data) {

    }
}
?>

My initial thought is that it's a bug; PHP isn't detecting that ConcreteFoo implements Foo when it is evaluating the method declaration it. I think this because when you run this code:

<?php
interface Foo {
    public function foo();
}

class ConcreteFoo implements Foo {
    public function foo() {

    }
}

$foo = new ConcreteFoo();

if ($foo instanceof Foo) 
{
    print 'w00t!';
} 
else 
{
    print 'FAIL!';
}
?>

it prints w00t! indicating ConcreteFoo is an instance of Foo.

Any insights into whether this behavior is correct or not?

like image 395
kulishch Avatar asked Dec 14 '12 03:12

kulishch


2 Answers

According to the docs, type hints must match exactly.

like image 191
Major Productions Avatar answered Sep 19 '22 04:09

Major Productions


The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error. And same rules for classes which extends abstract classes.

Please, see in see in details here, see here too

And this is right behaviour \ logic.

check here Abstract types are useful in that they can be used to define and enforce a protocol; a set of operations which all objects that implement the protocol must support.

if we assume that your code will work without exception, then we have following problem: ConcreteFooMapper can't use instances of some class ConcreteFoo2 implements Foo as parameter for load method, but should (by Abstract class definition)

Also, if you use same signature, it not a problem really, cause all class \ type info available. Please, check following code

<?php
interface Foo {
        public function foo();
}

class ConcreteFoo implements Foo {
        public function foo() {
        }
}

abstract class AbstractFooMapper {
        abstract public function load(Foo $entity, array $data);
}

class ConcreteFooMapper extends AbstractFooMapper {
        public function load(Foo $entity, array $data) {
                var_dump($entity instanceof Foo);
                var_dump($entity instanceof ConcreteFoo);
        }

}

$someConcreteFoo = new ConcreteFoo();
$someFooMapper = new ConcreteFooMapper();

$someFooMapper->load($someConcreteFoo, array('somekey' => 'somevalue'));
// output
// bool(true) bool(true)  

?>
like image 38
Vadim Avatar answered Sep 21 '22 04:09

Vadim