On Tue, Nov 25, 2014 at 11:13 PM, Marc Bennewitz <dev@mabe.berlin> wrote:

>
> Am 25.11.2014 um 22:43 schrieb Levi Morrison:
>
>  On Tue, Nov 25, 2014 at 2:07 PM, Marc Bennewitz <dev@mabe.berlin> wrote:
>>
>>> I think it's required to do the type check on runtime (Option 2) because
>>> one of the use cases for return type-hint are factories and such often do
>>> instantiation in base of unknown string values:
>>>
>>> class MyFactory {
>>>      public static function factory($name) : AdapterInterface {
>>>          $class = 'MyNamespace\Adapter\' . $name;
>>>          return $class();
>>>      }
>>> }
>>>
>> It seems that I did not explain this clearly enough; I apologize. The
>> variance has to do with the declared type in the function signature
>> when inheritance is involved, not the type of the value returned by
>> the function.
>>
>> For instance, under any of the three options this code will work just
>> fine:
>>
>> class Foo {}
>> class Goo  extends Foo {}
>>
>> class FooFactory {
>>      function create(): Foo { return new Goo(); }
>> }
>>
>> As long as the return value from FooFactory::create returns Foo or a
>> subtype of Foo (such as Goo), then it will work.
>>
>> The variance that is under discussion in this thread is about the
>> declared return type in the signature:
>>
>> class GooFactory extends FooFactory {
>>      function create(): Goo {}
>> }
>>
>> In this case, GooFactory::create() declares a return type of Goo,
>> which is a subtype of Foo [the return type of the inherited method
>> FooFactory::create()]. This is a covariant return type.
>>
>> If we choose option 3, the only possible return type for
>> GooFactory::create is Foo.
>>
>> Hopefully this clarifies the issue.
>>
> Yes it does - thank you for explanation - my mistake :/
>
> Option 3 is a no go not from OOP perspective and from consistency pov as
> we already allow this in type-hint:
>
> class FooFactory {
>     function create(Foo $foo): Foo { return $foo; }
> }
>
> class GooFactory extends FooFactory {
>     function create(Goo $goo): Goo { return $goo; }
>
> }
>

This is not correct. Parameter typehints in PHP are invariant, so you are
not allowed to change them during inheritance. However LSP violations
during inheritance of *non-abstract* methods currently uses a very low
error level (E_STRICT), so you probably didn't notice. If you try the same
thing with an interface method or an explicitly abstract method, you will
receive a fatal error:

interface I1 {
    function foo(A $a);
}
class C1 implements I1 {
    function foo(B $b) { ... }
}

This code snippet will result in a fatal error, because it violates type
invariance.

Nikita

Reply via email to