Hello all,
I hope the subject is not misleading. Please look at the following code:
<?php
class A { }
class B extends A { }
interface C {
function foo(A $a);
}
class D implements C {
public function foo(B $b) {
}
}
This code produces a "Fatal error: Declaration of D::foo() must be
compatible with C::foo(A $a) in /xyz/inheritance.php on line 10"
(see http://3v4l.org/l2M0f).
I don't get the reason for that behavior (and I could not find any
documentation about that, at least not at
http://php.net/manual/en/language.oop5.typehinting.php).
I have already found https://bugs.php.net/bug.php?id=42330 but Derick's
response does not help me and the linked file cannot be accessed
anymore.
I'd say that it is absolutely legal to define a more specialized
type in a child or implementing class, or would this have any bad
side effects?
Thanks and best regards
Christian
Hello all,
I hope the subject is not misleading. Please look at the following code:
<?php class A { } class B extends A { } interface C { function foo(A $a); } class D implements C { public function foo(B $b) { } }
This code produces a "Fatal error: Declaration of D::foo() must be
compatible with C::foo(A $a) in /xyz/inheritance.php on line 10"
(see http://3v4l.org/l2M0f).I don't get the reason for that behavior (and I could not find any
documentation about that, at least not at
http://php.net/manual/en/language.oop5.typehinting.php).I have already found https://bugs.php.net/bug.php?id=42330 but Derick's
response does not help me and the linked file cannot be accessed
anymore.I'd say that it is absolutely legal to define a more specialized
type in a child or implementing class, or would this have any bad
side effects?Thanks and best regards
Christian
Interesting that you bring this up today, I was literally talking to
NikiC about this yesterday.
This is what is called a covariant method argument type, and the
reason that it is invalid is because if you pass an instance of D, to
function that allows anything implementing C, then it would be
acceptable to call foo() with an instance of A.
The relevant article on wikipedia:
https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Covariant_method_argument_type
Hello all,
I hope the subject is not misleading. Please look at the following code:
<?php class A { } class B extends A { } interface C { function foo(A $a); } class D implements C { public function foo(B $b) { } }
This code produces a "Fatal error: Declaration of D::foo() must be
compatible with C::foo(A $a) in /xyz/inheritance.php on line 10"
(see http://3v4l.org/l2M0f).I don't get the reason for that behavior (and I could not find any
documentation about that, at least not at
http://php.net/manual/en/language.oop5.typehinting.php).I have already found https://bugs.php.net/bug.php?id=42330 but Derick's
response does not help me and the linked file cannot be accessed
anymore.I'd say that it is absolutely legal to define a more specialized
type in a child or implementing class, or would this have any bad
side effects?
This is because parameters are not covariant, they are usually
invariant or contravariant.
Almost certainly you have no clue what that actually means; it's okay,
most people don't. Just go read and learn about them and learn for
yourself why parameter types are not covariant.
Hello all,
I hope the subject is not misleading. Please look at the following code:
<?php class A { } class B extends A { } interface C { function foo(A $a); }
Here you say "any A can be passed at argument"
class D implements C { public function foo(B $b) {
here you say "only a subset of A can be passed as argument"
Thus having
function bar(C $c) {
$a = new A();
$c->foo($a);
}
might work or might not work as $c might be an instance of D. Thus
breaks the Liskov Substitution Principle
http://en.wikipedia.org/wiki/Liskov_substitution_principle
doing it the other way round would work
interface E {
function foo(B $b);
}
class F implements E {
public function foo(A $a) {
}
}
as any B satisfies the is-a requirement compared to A, so everything
valid for E::foo() is valid for F::foo(), too. Along with other subtypes
to A.
johannes
From: Johannes Schlüter [mailto:johannes@schlueters.de]
Thus having
function bar(C $c) { $a = new A(); $c->foo($a); }
might work or might not work as $c might be an instance of D. Thus
breaks the Liskov Substitution Principle
http://en.wikipedia.org/wiki/Liskov_substitution_principle
Oh, now I see. Thanks fort he example, that helped ;)
Christian
Christian Stoller wrote (on 17/09/2014):
I'd say that it is absolutely legal to define a more specialized
type in a child or implementing class, or would this have any bad
side effects?
Here is a StackOverflow question discussing exactly this issue, which
includes why you can't do that with an interface contract, and some
suggestions on what you might want to do instead:
http://stackoverflow.com/q/21665795/157957
--
Rowan Collins
[IMSoP]