# Exception / trace member

- Thread: https://externals.io/message/7271
- Original archive: https://news-web.php.net/php.internals/7271
- Started by Stephane Drouard on 2004-01-22T14:46:13+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #7271 — Stephane Drouard — 2004-01-22T14:46:13+00:00

URL: https://externals.io/message/7271#7271

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

---

## #7280 — Marcus Boerger — 2004-01-22T19:29:07+00:00

URL: https://externals.io/message/7271#7280 · In reply to: #7271

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

---

## #7282 — Marcus Boerger — 2004-01-22T19:56:54+00:00

URL: https://externals.io/message/7271#7282 · In reply to: #7280

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:

> > […]

> > […]

> > […]

> > […]

> > […]

> > […]
?>>>

> > […]

> > […]

> > […]

> > […]

> > […]

> > […]

> > […]

> > […]

> > […]




> -- 
> Best regards,
>  Marcus                            mailto:helly@php.net




-- 
Best regards,
 Marcus                            mailto:helly@php.net
