2014-11-25 23:42 GMT+01:00 Nikita Popov <nikita....@gmail.com>: > 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. > > Let's not compare these two:
* Parameter types are contravariant, otherwise they are not type sound. Yet, contravariance in general is of little interest (I cannot think of any practical example), so invariance is a good compromise. * Return types are covariant. There are many useful examples already mentioned in this mailing list. http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Covariant_method_return_type Lazare INEPOLOGLOU Ingénieur Logiciel