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