[PHP-DEV] Implementing interface method with child class in parameter def (Bug #42330)

2014-09-17 Thread Christian Stoller
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


Re: [PHP-DEV] Implementing interface method with child class in parameter def (Bug #42330)

2014-09-17 Thread Leigh
On 17 September 2014 15:52, Christian Stoller stol...@leonex.de wrote:
 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

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implementing interface method with child class in parameter def (Bug #42330)

2014-09-17 Thread Levi Morrison
On Wed, Sep 17, 2014 at 8:52 AM, Christian Stoller stol...@leonex.de wrote:
 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.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Implementing interface method with child class in parameter def (Bug #42330)

2014-09-17 Thread Johannes Schlüter
On Wed, 2014-09-17 at 16:52 +0200, Christian Stoller wrote:
 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



-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



RE: [PHP-DEV] Implementing interface method with child class in parameter def (Bug #42330)

2014-09-17 Thread Christian Stoller
From: Johannes Schlüter [mailto:johan...@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


Re: [PHP-DEV] Implementing interface method with child class in parameter def (Bug #42330)

2014-09-17 Thread Rowan Collins

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]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php