Exceptions instead of Fatal Error when calling non existent method?

php.internals

=?ISO-8859-1?Q?Fredrik_Holmstr=F6m?=

18 years ago
Hi! I've never posted on internal before, but I've been a long time reader of it. I've been using PHP for a long time, I think it all started back in 2000 sometime, anyway - this is hardly a place to put my entire php biography up for show, so I'll jump right to the action. Ever since PHP5 and the much improved object model (exceptions, and what not) there has been one thing missing (at least for me) the whole time. When you call a method (and function, but this doesn't really matter from an OO perspective) on an object that does not exist, you get a "Fatal error: Call to undefined method Foo::bar() in C:\www\index.php on line 4". What I would like to argue/request is that there should be a way to get an exception thrown when you call a non existent method on an object, since it's not possible to catch E_ERROR with a user defined function using set_error_handler() I can't see anyway to accomplish this in the current implementation? Why do you want this? To allow for "true" duck typing (which I think fits good into PHP's dynamic nature) without having the risk of your application running into fatal errors and now having to use if(method_exists($obj, $method)) on every call I want to make. I've come up with a couple of suggestions on how this could be implemented, but I'm not very good with the inner workings of php / zend engine (I've read parts of Saras book, but that's about it) so I don't know how hard (or easy) any of these suggestions would be to implement: a) Change the error raised when running into an unknown method call into it's own type that is fatal if not caught by an user defined error handler? b) Change the error raised to E_WARNING c) Change the error raised to E_RECOVERABLE_ERROR which as far as I can make out is possible to handle with a user defined error handler? d) Make the engine throw an exception of a special type when an unknown method is called, possibly provide an php.ini-setting so you can toggle between the old (E_ERROR) and the new (UnkownMethodException) to not break BC? Thanks for reading my message, regards Fredrik.

Alain Williams

18 years ago
On Mon, Dec 31, 2007 at 12:28:23PM +0100, Fredrik Holmström wrote:
> Hi! > > I've never posted on internal before, but I've been a long time reader > of it. I've been using PHP for a long time, I think it all started > back in 2000 sometime, anyway - this is hardly a place to put my > entire php biography up for show, so I'll jump right to the action. > > Ever since PHP5 and the much improved object model (exceptions, and > what not) there has been one thing missing (at least for me) the whole > time. When you call a method (and function, but this doesn't really > matter from an OO perspective) on an object that does not exist, you > get a "Fatal error: Call to undefined method Foo::bar() in > C:\www\index.php on line 4". > > What I would like to argue/request is that there should be a way to > get an exception thrown when you call a non existent method on an > object, since it's not possible to catch E_ERROR with a user defined > function using set_error_handler() I can't see anyway to accomplish > this in the current implementation?
What is wrong with __call() ? See: http://www.php.net/manual/en/language.oop5.overloading.php
-- Alain Williams Linux Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer. +44 (0) 787 668 0256 http://www.phcomp.co.uk/ Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php Chairman of UKUUG: http://www.ukuug.org/ #include <std_disclaimer.h>

=?ISO-8859-1?Q?Fredrik_Holmstr=F6m?=

18 years ago
>What is wrong with __call() ? >See: > http://www.php.net/manual/en/language.oop5.overloading.php
Hi! Yes, I'm aware of call() but it's very slow. Also it's not feasible to have *all* my classes extend a base class with the a call containing a throw InvalidMethodException, and what if I need to use 3rd party libraries that make use of call in some other way. __call() is a hack, that, at best, work 50% of the time. Regards, Fredrik.

Mikko Koppanen

18 years ago
> Yes, I'm aware of call() but it's very slow. Also it's not feasible to > have > *all* my classes extend a base class with the a call containing a throw > InvalidMethodException, and what if I need to use 3rd party libraries that > make use of call in some other way. __call() is a hack, that, at best, > work > 50% of the time. >
Calling methods without knowing that they exist sounds like a hack to me. How about using abstract classes or interfaces?
-- Mikko Koppanen

=?ISO-8859-1?Q?Fredrik_Holmstr=F6m?=

18 years ago
> 2007/12/31, Mikko Koppanen > Calling methods without knowing that they exist sounds like a hack to me. How about using abstract classes or interfaces?
If you look at, for example, python - calling methods that don't *know* exists is common practice, it's not a hack from my point of view. It's just easier to ask forgiveness then permission, to quote Hopper. I never understood the direction PHP is heading with type hinting, static binding (SPL-Types?), etc. While I don't directly oppose it I don't see any reason for it. I just thought that adding some type of ability to handle unknown method calls (without forcing *every* class to implement __call() in a specific way) would be a nice way for those of us that want to continue to use php as the dynamic, duck-typed language we learned. Maybe it will fall on deaf ears, but I thought it was worth a chance and at least propose it here on internals. Regards, Fredrik.

Antony Dovgal

18 years ago
On 31.12.2007 15:09, Fredrik Holmström wrote:
>> 2007/12/31, Mikko Koppanen >> Calling methods without knowing that they exist sounds like a hack to me. How about using abstract classes or interfaces? > > If you look at, for example, python - calling methods that don't > *know* exists is common practice, it's not a hack from my point of > view. It's just easier to ask forgiveness then permission, to quote > Hopper. > > I never understood the direction PHP is heading with type hinting, > static binding (SPL-Types?), etc. While I don't directly oppose it I > don't see any reason for it. I just thought that adding some type of > ability to handle unknown method calls (without forcing *every* class > to implement __call() in a specific way)
There is no need to implement __call() in every class,. Just make sure their parent class implements it. Changing PHP's behavior in a backward-incompatible way that would affect everyone and *forcing everyone* to use exceptions seems to be really bad idea, especially taking into account that your problem can be easily solved without it.
-- Wbr, Antony Dovgal

=?ISO-8859-1?Q?Fredrik_Holmstr=F6m?=

18 years ago
> There is no need to implement __call() in every class,. > Just make sure their parent class implements it.
Yes, I'm well aware of that - but that doesn't really help when taking into account 3rd party libraries or places where it's not possible because you don't have control over the base class.
> Changing PHP's behavior in a backward-incompatible way that would affect > everyone and *forcing everyone* to use exceptions seems to be really bad > idea, especially taking into account that your problem can be easily solved > without it.
In my original post I proposed several ways that would not be backwards incompatible, and maybe I put the subject on the original message wrong - the key here isn't really exceptions but the ability to handle unknown method calls without taking the entire process down with it. Anyway this will be my last post on the subject since I don't want to spam the list and I think I've expressed all my opinions about it clearly. Regards, Fredrik.

Stefan Walk

18 years ago
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Monday 31 December 2007 13:48:52 Antony Dovgal wrote:
> Changing PHP's behavior in a backward-incompatible way that would affect > everyone and *forcing everyone* to use exceptions seems to be really bad > idea, especially taking into account that your problem can be easily solved > without it.
What exactly is the backwards compatibility break here? Without the change, the code simply dies ... if you don't catch the exception, the code simply dies ... except you get a backtrace now and can handle the exception if you want to. Regards, Stefan -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFHeO5UpPjfcppEficRAng4AJ4v4G+PyT07cQTYupTgKFnOA130yQCeKWYy E2tzkWAHOmIKDc/CZw7Dtjw= =ArZH -----END PGP SIGNATURE-----

Amir Abiri

18 years ago
Also, it will allow PHP applications to recover more gracefully from this sort of error. A properly designed PHP application that already has global catch blocks and some 500 error pages will have this sort of error come under that same error handling process rather then give an ugly blank page. I think it will make PHP look more professional altogether. [Ahm: Also new here on the list :-)] A

Sebastian Nohn

18 years ago
Fredrik Holmström wrote:
> Why do you want this? To allow for "true" duck typing (which I think > fits good into PHP's dynamic nature) without having the risk of your > application running into fatal errors and now having to use
There are way more profane use cases like nicely handling such errors to display some nice end user messages, handle logging events etc. It may be possible to recover from more (all?) fatal errors.
> a) Change the error raised when running into an unknown method call > into it's own type that is fatal if not caught by an user defined > error handler?
That would IMHO be the best way. It would even be better if all uncaught exceptions would at least raise an E_NOTICE or even E_WARNING.
> b) Change the error raised to E_WARNING > > c) Change the error raised to E_RECOVERABLE_ERROR which as far as I > can make out is possible to handle with a user defined error handler?
These are not the way to go in my eyes.
> d) Make the engine throw an exception of a special type when an > unknown method is called, possibly provide an php.ini-setting so you > can toggle between the old (E_ERROR) and the new > (UnkownMethodException) to not break BC?
The second best and worst option. Please not another ini-Setting. - Sebastian

Derick Rethans

18 years ago
On Mon, 31 Dec 2007, Fredrik Holmström wrote:
> What I would like to argue/request is that there should be a way to > get an exception thrown when you call a non existent method on an > object, since it's not possible to catch E_ERROR with a user defined > function using set_error_handler() I can't see anyway to accomplish > this in the current implementation?
E_ERROR should during normal runs of your program *never* be hit in the first place. If it is something critical that still can be handled, E_RECOVERABLE_ERROR should be used inside PHP. If that is not the case, please let us now and we can address that. As for the calling undefined methods, __call() is your friend. regards, Derick