base class

php.internals

Stephane Drouard

22 years ago
PHP implements an "stdClass". I expected that: * this was the base class for all classes, even if they do not explicitly "extends stdClass", * this class implemented all the "standard" methods (__construct(), __destruct(), ...). In the PHP5 presentation, it is mentionned the interest of unified constructors. Currently it is not possible to call parent::__construct() if the class does not derived from another one, or none of its parent implements a constructor. Another problem: when you change a class implementation and decide to now implement a constructor, you have to review all its derived classes. Which finally limits the benefit of unified constructors. I think all classes should be derived from a common base class (stdClass or a new dedicated one), even if it's not explicitly written. This base class should also implement all the standard methods: __construct() Empty. __destruct() Empty. __clone() Does the bit for bit copy of the object. Note: I also added a post concerning a new cloning implementation proposal. In that case, __clone() would be empty. __toString() To be compatible with the current implementation, this method should return "Object id #n". However I would prefer it returns the class name instead, which gives a more useful piece of information than it's ID. __get() Display the "Notice: Undefined property ..." and returns NULL. __set() Create a new member (public). Note: I would appreciate that a notice is also displayed, because I don't consider this is a normal way to create members. __call() Generates a "Fatal error: Call to undefined method ...". Regards, Stephane

Christian Schneider

22 years ago
Stephane Drouard wrote:
> Currently it is not possible to call parent::__construct() if the
class does not derived
> from another one, or none of its parent implements a constructor.
I agree that it should always be possible to call parent::__construct() (at least if a base class exists :-)).
> __construct() > __destruct() > Empty.
Agreed. If the method actually exists or is somehow magic is an implementation detail. But one should always be able to call parent::__construct/__destruct.
> __clone() > Does the bit for bit copy of the object.
I think this and all other 'magic' methods you mention should be empty. Right now a bit cloning is done before __clone() is called, I can live with the minimal performance penalty this might cause. Keeps things simple and calling a non-implemented parent::__ never causes any harm like this. - Chris

Marcus Börger

22 years ago
Hello Stephane, Thursday, January 22, 2004, 3:48:19 PM, you wrote:
> PHP implements an "stdClass". I expected that: > * this was the base class for all classes, even if they do not explicitly "extends stdClass",
nope, there is absolutely no reason for that
> * this class implemented all the "standard" methods (__construct(), __destruct(), ...).
all __* are magic functions they must not exist and are not meant to be called directly (which seems to be your problem). It is just easy: never call a __* method directly with the exception neing __clone() which works slightly different.
> In the PHP5 presentation, it is mentionned the interest of unified > constructors. Currently it is not possible to call parent::__construct() > if the class does not derived from another one, or none of its parent > implements a constructor.
Well you design a class tree/framework and should know what you have done. If not use reflection.
> Another problem: when you change a class implementation and decide to > now implement a constructor, you have to review all its derived classes. > Which finally limits the benefit of unified constructors.
A change is a change.
> I think all classes should be derived from a common base class > (stdClass or a new dedicated one), even if it's not explicitly written. > This base class should also implement all the standard methods:
[...] That would slow down execution ***very*** much and makes absolutely no sense at all. If you want a base class for your classes do it. Fell free. Do implement whatever classtree/framework you whish to have. But don't misuse internal classes.
-- Best regards, Marcus mailto:helly@php.net

Christian Schneider

22 years ago
Marcus Boerger wrote:
> Well you design a class tree/framework and should know what you have done. > If not use reflection.
So to be able to later add a constructor to a base class one would be stuck with one of two options: 1) have __construct() in all classes from the start, even if it's empty. Ugly and stupid. Not even Java forces one to do that :-) 2) Use reflection in all extending classes to check if a constructor exists. Inacceptable, a joke at best.
> A change is a change.
OO is about extending classes without having to touch users of the class if the interface remains the same. Arguing that adding a constructor changes the interface is silly, especially if it is a parameterless one.
> That would slow down execution ***very*** much and makes absolutely no > sense at all. If you want a base class for your classes do it. Fell free.
I don't buy that: The place where zend_error(E_ERROR, "Can not call constructor"); is done could easily just ignore the call. Maybe it could be turned into E_NOTICE or E_STRICT for people who want to be notified about such calls. I'll post a patch on the WE if noone else is doing it. - Chris

Stephane Drouard

22 years ago
Marcus, The idea behind this kind of request is to speed up development time. And the way a language and its base classes are implemented could really help to reach this goal. When you write "a change is a change", you're right. But the way you have written your code could really reduce the risk of bugs. And systematically calling parent::... is one of it. I also understand when you consider as a non sense calling an empty method which slows down execution for nothing. Except that personally I really favour develop time rather than execution speed. Upgrading a computer is less expensive than spending hours to fix bugs. Implementing a common base class with empty methods (or Chris' proposal, just do not report error) does not impact performance (just don't call them), but allows people having a different view on programming to do it. Finally my request to implement it within PHP would limit the number of class trees, all world wide classes would have the same base class. Nice OOP vision, isn't it ;-) Regards, Stephane

Marcus Börger

22 years ago
Hello Stephane, your right with comparing development time to computer performance (total cost of ownership model). So feel free to remember me as soon as we start developing php 5.1. Maybe we can add somthing that lets you call non present magical methods (__construct/__destruct/__clone) even if they are not present without a huge waste of time in execution. marcus Friday, January 23, 2004, 11:53:02 AM, you wrote:
> Marcus,
> The idea behind this kind of request is to speed up development time. > And the way a language and its base classes are implemented could really > help to reach this goal.
> When you write "a change is a change", you're right. But the way you > have written your code could really reduce the risk of bugs. And > systematically calling parent::... is one of it.
> I also understand when you consider as a non sense calling an empty > method which slows down execution for nothing. > Except that personally I really favour develop time rather than > execution speed. Upgrading a computer is less expensive than spending > hours to fix bugs.
> Implementing a common base class with empty methods (or Chris' > proposal, just do not report error) does not impact performance (just > don't call them), but allows people having a different view on programming > to do it.
> Finally my request to implement it within PHP would limit the number of > class trees, all world wide classes would have the same base class. Nice > OOP vision, isn't it ;-)
> Regards, > Stephane
-- Best regards, Marcus mailto:helly@php.net

Christian Schneider

22 years ago
Stephane Drouard wrote:
> Implementing a common base class with empty methods (or Chris' proposal, just do not > report error) does not impact performance (just don't call them), but allows people > having a different view on programming to do it.
Here's a little patch which changes "Can not call constructor" from E_ERROR to E_NOTICE and continues execution: http://cschneid.com/php/php5/undefined_constructor_call.patch Feel free to point out problems with this patch and I'll spend more time on it. I think it is a very bad idea to release PHP 5 like this. Look at the mess caused by the pre-PHP 4 feature freeze back then, especially the copy-on-assign decision which was a lot more painful to fix in PHP 5 than if it would have been done right in PHP 4. We should _not_ repeat this mistake. There's already enough problems with PHP 5 (e.g. no clean transition for __clone() from PHP 4 to PHP 5 due to the PHP 4.3 feature freeze), let's clean up as much as possible. It will make life for millions of PHP users so much easier if they can rely on some basic facts like parent::__constructor() and not having to write their own base class just to add an empty constructor. I believe a language should make life for programmers easy, not hard. PHP is almost there. - Chris

Marcus Börger

22 years ago
Hello Christian, I can very much understand the drive behind this whish. The patch consists of two parts. The first part is generating an error message in case no constructor is available. He uses E_NOTICE while i would prefer E_STRICT there. Then the second part is a bit strange. It looks like if we could ignore other functions/methods with the patch.that doesn't look right. From my perspective skipping a function should only work for __construct and __destruct and only in construction (new) and destruction (unset) of the object. From my short look it seems the whole thing should be done in another way. The prblem i see is that it is hard to check whether we are in constructor or destructor and are about calling inherited once. We cannot ignore any other method or function calls. To enforce that the change only affects construtor and destructor chains we'd have to add EG states for constructor and destructor calling and push/pop them when dealing with eval etc. This adds a lot of complexity which i would like to prevent. marcus Sunday, January 25, 2004, 11:29:49 PM, you wrote:
> Stephane Drouard wrote: >> Implementing a common base class with empty methods (or Chris' proposal, just do not >> report error) does not impact performance (just don't call them), but allows people >> having a different view on programming to do it.
> Here's a little patch which changes "Can not call constructor" from > E_ERROR to E_NOTICE and continues execution: > http://cschneid.com/php/php5/undefined_constructor_call.patch
> Feel free to point out problems with this patch and I'll spend more time > on it.
> I think it is a very bad idea to release PHP 5 like this. Look at the > mess caused by the pre-PHP 4 feature freeze back then, especially the > copy-on-assign decision which was a lot more painful to fix in PHP 5 > than if it would have been done right in PHP 4. We should _not_ repeat > this mistake. There's already enough problems with PHP 5 (e.g. no clean > transition for __clone() from PHP 4 to PHP 5 due to the PHP 4.3 feature > freeze), let's clean up as much as possible.
> It will make life for millions of PHP users so much easier if they can > rely on some basic facts like parent::__constructor() and not having to > write their own base class just to add an empty constructor.
> I believe a language should make life for programmers easy, not hard. > PHP is almost there.
> - Chris
-- Best regards, Marcus mailto:helly@php.net

Christian Schneider

22 years ago
Marcus Boerger wrote:
> I can very much understand the drive behind this whish. The patch consists > of two parts. The first part is generating an error message in case no > constructor is available. He uses E_NOTICE while i would prefer E_STRICT
Both E_NOTICE or E_STRICT are fine with me. Whatever people feel is more appropriate.
> there. Then the second part is a bit strange. It looks like if we could > ignore other functions/methods with the patch.that doesn't look right.
No, it avoids the segfault caused by the previous patch because in that case EX(function_state).function never gets set. I don't change anything for other function calls as function is always set (otherwise it would have caused a segfault w/o my patch anyway). - Chris

Christian Schneider

22 years ago
Any chance the patch at http://cschneid.com/php/php5/undefined_constructor_call.patch will be applied? I find it a rather crucial patch for PHP5 but I'm happy to listen to people telling me otherwise, as long as I get some reponse :-) - Chris

Stephane Drouard

22 years ago
Chris, For sure I can't answer to your question, but why would you only implement it to construtors? My original request was that all classes inherit from a base class provided by PHP (even if not explicitly written), and that this base class implements all magic methods in the appropriate way (see my original message). Because PHP won't implement such a base class, I don't think it's interresting to be able to call parent::__construct() without error. Just provide your base class to do so. I just proposed PHP provides this class to be sure all classes inherits from the same base class, and not everybody develops their own. That way, new PHP features would be implemented in this class and automatically supported by all classes. Regards, Stephane

Christian Schneider

22 years ago
Stephane Drouard wrote:
> For sure I can't answer to your question, but why would you only implement it > to construtors?
That's where I think it is most needed. The other magic methods are already less important but if there is an agreement to this I could also whip a patch together for those. I just try to go step by step.
> Because PHP won't implement such a base class, I don't think it's interresting > to be able to call parent::__construct() without error. Just provide
your base
> class to do so.
I disagree. I think it's silly to force people to provide a base class just for this. And I think parent::__construct() covers at least 80%. IMHO PHP doesn't need to be perfect in an academic OO sense but needs to provide what the majority of users need. - Chris

Timm Friebe

22 years ago
On Thu, 2004-01-22 at 15:48, Stephane Drouard wrote: [...]
> I think all classes should be derived from a common base class > (stdClass or a new dedicated one), even if it's not explicitly > written.
This can be done in userland and should take a more or less skilled programmer 5 to 10 minutes. - Timm

Unnamed Person

22 years ago
So why must we all keep implementing it? On 23 Jan 2004, at 4:21 PM, Timm Friebe wrote:

Timm Friebe

22 years ago
On Sat, 2004-01-24 at 03:06, lingwitt@bellsouth.net wrote:
> So why must we all keep implementing it?
Well, because you'd probably not like it the way I'd like to see it (or the other way around), someone else probably prefers PEAR's, Horde's, $random_other_php_framework's solution, and so on. Plus, as was already said, and to which I agree, not every class should have a constructor. If it did, you'd have a noticeable and unnecessary memory overhead, especially when you're creating big amounts of objects. There are more reasons which do not necessarily have to do with performance or memory consumption but rather with how one thinks a base class should be designed - see what I mean by personal preferences? All in all, I don't think it would be a good idea if PHP forced this on you. What would be basically OK if you had the _option_ of having such a base class. But then again, why not simply write one for yourself? It's not like any programmer utilizing OOP *doesn't* use any sort of include(s) in where his/her classes reside. Add it there and you're all set up. It's basically the same with the built-in exception class. I can't have my own (at least not with the sexy-most name "Exception"). Then, in my (very personal) view I want it designed differently, and want to have it extend _my_ base class (which, incidentally, is called "Object" and does _not_ have constructor:)) - again, this is _my_ very personal feeling about how it should be - so I'll just have my own exception, which is perfectly OK and dealt with very well by the Zend Engine. I'm not the only PHP user out there with his or her own understanding of subtleties in class design (new Reflection_Class("xxx") vs. Reflection_Class::forName("xxx"). As for base classes, whip up Google, search for object.php and see for yourself. - Timm

Stephane Drouard

22 years ago
== Quote from Timm Friebe (thekid@thekid.de)'s article
> It's basically the same with the built-in exception class. I can't have > my own (at least not with the sexy-most name "Exception"). Then, in my > (very personal) view I want it designed differently, and want to have it > extend _my_ base class (which, incidentally, is called "Object" and does > _not_ have constructor:)) - again, this is _my_ very personal feeling > about how it should be - so I'll just have my own exception, which is > perfectly OK and dealt with very well by the Zend Engine.
Exception is a very good example why I think sharing a common base class is necessary (I also posted a message on that). Imagine I use my own exception base class, and you use your own. Now what will happen if I get some code from you? I will have to review all my code and verify everywhere I want to catch all the exceptions (kind of "finally" clause), if one of your exception classes could be thrown and then add your base class in the catch list. Not so easy and prone to bugs. To avoid that, either PHP should implement a generic catch (like C++ "catch(...)" or "finally") or we have to share the same base class, which could be empty or be an interface. Many OO languages impose base classes and, for sure, they can not implement all everybody needs, and may sometimes be contradictory with your expectation, but this is a constraint we should accept to simplify programming and particularly code sharing. Regards, Stephane

Marcus Börger

22 years ago
Hello Stephane, Saturday, January 24, 2004, 4:20:33 PM, you wrote:
> == Quote from Timm Friebe (thekid@thekid.de)'s article >> It's basically the same with the built-in exception class. I can't have >> my own (at least not with the sexy-most name "Exception"). Then, in my >> (very personal) view I want it designed differently, and want to have it >> extend _my_ base class (which, incidentally, is called "Object" and does >> _not_ have constructor:)) - again, this is _my_ very personal feeling >> about how it should be - so I'll just have my own exception, which is >> perfectly OK and dealt with very well by the Zend Engine.
> Exception is a very good example why I think sharing a common base > class is necessary (I also posted a message on that). Imagine I use my own > exception base class, and you use your own.
Well you should always by no exception derive your exception classes from the builtin exception class. Just because that class can do things you can never imlement in your scripts. And it allows some special handling because the engine knows all its internals. And yes this is very much different from normal class and stdClass.
> Now what will happen if I get some code from you? I will have to review > all my code and verify everywhere I want to catch all the exceptions (kind > of "finally" clause), if one of your exception classes could be thrown and > then add your base class in the catch list. Not so easy and prone to bugs. > To avoid that, either PHP should implement a generic catch (like C++ > "catch(...)" or "finally") or we have to share the same base class, which > could be empty or be an interface.
> Many OO languages impose base classes and, for sure, they can not > implement all everybody needs, and may sometimes be contradictory with > your expectation, but this is a constraint we should accept to simplify > programming and particularly code sharing.
> Regards, > Stephane
-- Best regards, Marcus mailto:helly@php.net

Timm Friebe

22 years ago
On Sat, 2004-01-24 at 16:13, Marcus Boerger wrote: [...]
> Well you should always by no exception derive your exception classes from > the builtin exception class. Just because that class can do things you can > never imlement in your scripts.
Care to elaborate? A userland implementation is attached. - Timm

Marcus Börger

22 years ago
Ah Timm, you ol' hacker! Looks pretty good. You capture like 99% i think :-) thanks for the nice cod marcus Saturday, January 24, 2004, 7:53:12 PM, you wrote:
> On Sat, 2004-01-24 at 16:13, Marcus Boerger wrote: > [...] >> Well you should always by no exception derive your exception classes from >> the builtin exception class. Just because that class can do things you can >> never imlement in your scripts.
> Care to elaborate? A userland implementation is attached.
> - Timm
-- Best regards, Marcus mailto:helly@php.net