The current implementation of class Exception has a private "trace" member, which is used to store the backtrace. But if you throw an exception of a derived class of Exception, print_r()
displays an empty "trace:private" member, as well as a "trace" (public) member that really holds the backtrace.
I deduce that the backtrace is executed/stored at the derived class level, explaining why a new public member is created.
Curriously, I have also noticed that "getTrace()" returns the public one, not the private one as expected.
This is not to report a bug, but to ask you not to fix it as it was intended ("trace" member as private). Indeed I use this "feature" (being able to modify the trace member) to hide an intermediate call:
<?
class SystemException extends Exception {
function __construct($message, $code) {
parent::__construct($message, $code);
// Hide trace of handler() call.
array_splice($this->trace, 0, 1);
$this->file = $this->trace[0]['file'];
$this->line = $this->trace[0]['line'];
}
static function handler($code, $message) {
throw new SystemException($message, $code);
}
}
set_error_handler(array('SystemException', 'handler'));
?>
That way, the reported error focuses on the real file and line, not on the uninteresting intermediate handler call.
In the current Exception class implementation, if both the "trace" member is private and getTrace() is final, it would be impossible to override the default behaviour. As a result, we would do our own exception base class, which goes against code reuse: need to redo all the things already done, just because the proposed class is not too open.
A second consequence, is that each time you use code you've got from "outside", it could implement its own exception base class, not using the provided Exception. If so, we won't be able to write generic code that guaranties to catch all exceptions (C++ "catch(...)" or Java "finally" not implemented in PHP5, so need to specify a class for catch).
The last point suggests me that PHP should guaranty that all thrown exceptions derive from Exception. It could be done in 2 ways:
1/ a fatal error when executing "throw new ...".
Problem: it's not easy to simulate all error conditions, so we may deliver code that was never tested on all its "throw" branches. As a result, the script will stop on a fatal error, even though it was intented to catch and handle exceptions in a clean way.
2/ even if the class is not explicitly derived from Exception, throwing it will make it derived from Exception.
Problem: an object of such a class will be an instance of Exception only after being thrown.
The 2nd is my prefered one, even if I understand it could not be so easy to implement.
One word about private and final: I don't think it's good programming to use them, except for security reasons. Not using them allows classes to be easily extended, in different directions, which is the goal of OOP.
Moreover, all members should be protected, not public, and accessed through (virtual) methods, which guaranties that everything can be overriden if needed.
Regards,
Stephane
Hello Stephane,
if this is really the case, well then i am the one to blame. I'll have a
look.
Thursday, January 22, 2004, 3:46:13 PM, you wrote:
The current implementation of class Exception has a private "trace"
member, which is used to store the backtrace. But if you throw an
exception of a derived class of Exception,print_r()
displays an empty
"trace:private" member, as well as a "trace" (public) member that really
holds the backtrace.
I deduce that the backtrace is executed/stored at the derived class
level, explaining why a new public member is created.
Curriously, I have also noticed that "getTrace()" returns the public
one, not the private one as expected.
This is not to report a bug, but to ask you not to fix it as it was
intended ("trace" member as private). Indeed I use this "feature" (being
able to modify the trace member) to hide an intermediate call:
<?
class SystemException extends Exception {
function __construct($message, $code) {
parent::__construct($message, $code);
// Hide trace of handler() call.
array_splice($this->trace, 0, 1);
$this->file = $this->trace[0]['file'];
$this->line = $this->trace[0]['line'];
}
static function handler($code, $message) {
throw new SystemException($message, $code);
}
}
set_error_handler(array('SystemException', 'handler'));
?>>
That way, the reported error focuses on the real file and line, not on
the uninteresting intermediate handler call.
In the current Exception class implementation, if both the "trace"
member is private and getTrace() is final, it would be impossible to
override the default behaviour. As a result, we would do our own exception
base class, which goes against code reuse: need to redo all the things
already done, just because the proposed class is not too open.
A second consequence, is that each time you use code you've got from
"outside", it could implement its own exception base class, not using the
provided Exception. If so, we won't be able to write generic code that
guaranties to catch all exceptions (C++ "catch(...)" or Java "finally" not
implemented in PHP5, so need to specify a class for catch).
The last point suggests me that PHP should guaranty that all thrown
exceptions derive from Exception. It could be done in 2 ways:
1/ a fatal error when executing "throw new ...".
Problem: it's not easy to simulate all error conditions, so we may
deliver code that was never tested on all its "throw" branches. As a
result, the script will stop on a fatal error, even though it was intented
to catch and handle exceptions in a clean way.
2/ even if the class is not explicitly derived from Exception, throwing
it will make it derived from Exception.
Problem: an object of such a class will be an instance of Exception only after being thrown.
The 2nd is my prefered one, even if I understand it could not be so easy to implement.
One word about private and final: I don't think it's good programming
to use them, except for security reasons. Not using them allows classes to
be easily extended, in different directions, which is the goal of OOP.
Moreover, all members should be protected, not public, and accessed
through (virtual) methods, which guaranties that everything can be
overriden if needed.
Regards,
Stephane
--
Best regards,
Marcus mailto:helly@php.net
Hello Stephane,
if this is really the case, well then i am the one to blame. I'll have a
look.
i looked into it - you were right - and i fixed it. Could you please test
current HEAD to verify i have fixed all issues? That would give me a better
feeling. And thanks for noticing this.
marcus
Thursday, January 22, 2004, 3:46:13 PM, you wrote:
The current implementation of class Exception has a private "trace"
member, which is used to store the backtrace. But if you throw an
exception of a derived class of Exception,print_r()
displays an empty
"trace:private" member, as well as a "trace" (public) member that really
holds the backtrace.
I deduce that the backtrace is executed/stored at the derived class
level, explaining why a new public member is created.
Curriously, I have also noticed that "getTrace()" returns the public
one, not the private one as expected.
This is not to report a bug, but to ask you not to fix it as it was
intended ("trace" member as private). Indeed I use this "feature" (being
able to modify the trace member) to hide an intermediate call:
<?
class SystemException extends Exception {
function __construct($message, $code) {
parent::__construct($message, $code);
// Hide trace of handler() call.
array_splice($this->trace, 0, 1);
$this->file = $this->trace[0]['file'];
$this->line = $this->trace[0]['line'];
}
static function handler($code, $message) {
throw new SystemException($message, $code);
}
}
set_error_handler(array('SystemException', 'handler'));
?>>>
That way, the reported error focuses on the real file and line, not on
the uninteresting intermediate handler call.
In the current Exception class implementation, if both the "trace"
member is private and getTrace() is final, it would be impossible to
override the default behaviour. As a result, we would do our own exception
base class, which goes against code reuse: need to redo all the things
already done, just because the proposed class is not too open.
A second consequence, is that each time you use code you've got from
"outside", it could implement its own exception base class, not using the
provided Exception. If so, we won't be able to write generic code that
guaranties to catch all exceptions (C++ "catch(...)" or Java "finally" not
implemented in PHP5, so need to specify a class for catch).
The last point suggests me that PHP should guaranty that all thrown
exceptions derive from Exception. It could be done in 2 ways:
1/ a fatal error when executing "throw new ...".
Problem: it's not easy to simulate all error conditions, so we may
deliver code that was never tested on all its "throw" branches. As a
result, the script will stop on a fatal error, even though it was intented
to catch and handle exceptions in a clean way.
2/ even if the class is not explicitly derived from Exception, throwing
it will make it derived from Exception.
Problem: an object of such a class will be an instance of Exception only after being thrown.
The 2nd is my prefered one, even if I understand it could not be so easy to implement.
One word about private and final: I don't think it's good programming
to use them, except for security reasons. Not using them allows classes to
be easily extended, in different directions, which is the goal of OOP.
Moreover, all members should be protected, not public, and accessed
through (virtual) methods, which guaranties that everything can be
overriden if needed.
Regards,
Stephane
--
Best regards,
Marcus mailto:helly@php.net
--
Best regards,
Marcus mailto:helly@php.net