Honestly, I think __construct should behave like any other method when specified abstract or via an interface.
I know you're thinking "But it's not an LSP violation in the constructor". But my assertion to that is that it's a violation of the contract that the abstract method / interface defined. If it's a violation of contract, I would expect to get a fatal error. After all, that's what a contract is for if not to enforce. Now, you could make the argument that it's impossible to enforce a contract (via type-hinting/instanceof) since there's no object at that point. So the contract isn't "signed". And that's the *only* reason that I could understand for wanting to change it from a fatal error to ignored. However, if that's taken, then I would expect to be notified that constructors are not enforced by the interface/abstract method. Perhaps raise a notice (or E_STRICT) in the interface on compile time that "__construct is not enforced by interfaces"... Additionally, what about other magic methods? Should they be handled separately? I could understand a contract to enforce __invoke and __toString, but what about the rest? Should they be specifiable in contract form (get/set/call/etc)? So, actually I'm not so sure on that myself. The Only use case I can think of I've used here: https://github.com/ircmaxell/PHP-CryptLib/blob/master/lib/CryptLib/Core/AbstractFactory.php#L51 Basically, it's an abstract factory that checks if a class name implements an interface before it will "register" the class. This is useful for implementing proxy patterns and the such. So we don't actually instantiate until later. But we want to be sure that when we do, we'll have the proper class implementing the proper interface. Since the factory will call `new` later, it needs to know the constructor is valid. So declaring the constructor in the interface actually makes sense there... So, my opinion is that either all magic methods (with the possible exception of __toString and __invoke) should be excluded from interface requirements, or none should. Either way is fine with me, but they should be consistent. And I do lean on the side that the contract is the contract, and if you change (overload) a method, you're breaking the contract. And if you specify the constructor in the contract (you don't have to), you should be bound to that contract... So I think 5.4's behavior is the proper one. I won't be upset if it changes, but if it does I think the rest of the magic methods (two mentioned withstanding) should change as well... Just my $0.02... Anthony On Thu, Nov 17, 2011 at 4:12 PM, Ralph Schindler <ra...@ralphschindler.com> wrote: > Hey All, > > Concerning RC1, __construct() and https://wiki.php.net/rfc/prototype_checks > > I think we need to round out this discussion on the __construct() signature > checking in 5.4. The current behavior (RC1) feels very wrong with respect > to PHP's class based, single inheritance, multiple interface, no method > overloading, allowed method-overriding nature. > > Constructors themselves, specifically in PHP, are not explicitly statically > marked, but are "special" (even though they are part of the instance API, > and are callable- we'll consider this an implementation detail). In > general, constructor signatures have never been (and rightfully so) governed > by the LSP. Why? For a few reasons: > > 1) before calling new(), you actually don't have a subtype (yet)- the > subtype is a *product* of new() > > 2) when you call new(), you know the exact subtype you're dealing with. > > 3) only subtypes who implement or override __construct() can know how to > prepare a stateful subtype. In other words, parents can't know how to > create subtypes who implement __construct() and subtypes shouldn't be > concerned with the implementation details of how a parent creates types when > a subtype has overridden __construct(); > > 4) LSP deals with behaviors and expectations of types (read: objects), > since the constructor is generally considered "static" in nature, a form of > factory specific to the type its defined within, and since in PHP you can't > do (SomeClass instanceof SomeType) and since (is_a('SomeClass', 'SomeType') > doesn't make much sense in the context of classes), the constructor is not > subject to instance "behavior" rules. > > In general, developers shouldn't be putting abstract constructors inside an > abstract class nor should they be putting constructors inside interfaces- > this is a well accepted bad practice. (Neither c# or java allow this- of > course they do have the ability to overload methods in classes for the > record. In fact, static methods are not allowed either.) > > That said, we really should consider removing this limitation from > constructor signature checking. Not only is it a BC break, it doesn't make > sense in the context of PHP. > > Thoughts? > > Thanks, > Ralph Schindler > > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php