On Mon, Jul 28, 2025 at 1:17 PM Tim Düsterhus <t...@bastelstu.be> wrote:

> I'm afraid I don't quite understand what actual goal you intend to solve
> with the proposal. The description of your use case is very abstract,
> can you provide a real-world example of a use-case you want to enable?
>
> Best regards
> Tim Düsterhus
>

Sure.

Imagine 2 PHP services:

- backend monolith
- mailer

At some condition the "backend" makes an HTTP request to the "mailer".
The "mailer" answer with corresponding HTTP status, RPC body or in another
way.

When something goes wrong mailer responses with:
- status
- error message
- error trace

On the "backend" side we may inform the user that HTTP request failed:
- check for response status
- create an exception
-- with the error message in the "message" prop
-- and with the error trace in a custom prop, e.g. $externalTrace

Our exception renderer is quite powerful and renders all the chained errors
one by one:
```
Error "$e->getMessage()" occurred on the line "$e->getLine()"...
- During handling another exception: "$e->getPrevious()->getMessage()" on
the line "$e->getPrevious()->getLine()"...
-- During handling another exception:
"$e->getPrevious()->getPrevious()->getMessage()"

and so on.

Unfortunately, dumping all the properties of an exception is not possible:
there may be cycled references or just not readable bytes.
So, I should create a workaround (as many in this thread):
- Handle a particular class separately, reading a custom property,
converting the traces to some PHP-like form
- Or create an interface for such exceptions
- Or append the traces to the message string
- Or just dump the traces to the log and make users to open logs

Instead, users may
- Construct an exception from the external structure: message and trace
- Raise an exception like "HttpClientException" and passing the exception
from the previous point as a "previous" exception

After that an error renderer may render the traces as a regular chain of
exceptions, even if there are traces that are not related to the current
project.

Moreover, traces may come from another language like Go/Python/Java/etc.
They still may be accessible and useful to the end user.

Of course I'm not talking about production systems and showing traces to
everyone. As usual, they should be accessible only for developers.

This is my real case of using Temporal with a PHP server.
When something fails, you can access the traces from a custom exception
property / get looong "message".

Here some code snippets:

function req($url, $params) {
    $resp = $client->get($url, $params);
    if ($resp->status > 300) {
        $parsed = json_decode($resp->getBody());
        $prev = new Exception(message: $parsed['message'], trace:
$parsed['trace']); // or create a separate MyException and set trace there,
or externally with setTrace()
        throw new ClientHttpException("HTTP request to the $url was
failed", previous: $prev); // chain traces to the 3rd party
    }
}

{message: "...", trace: [...]} isn't contracted by PHP, a library should
parse it itself.

------


Moving further, there is an era of long-running apps. Coroutines also come
soon.
We may choose between classic exceptions with the "stack" trace and
modified exceptions with a custom-edited trace: prepend/append traces with
the coroutine-scope name or clean application bootstrap trace.
I'm not sure about mutating a complete trace of an exception, but still as
a case of usage.

-- 
Best regards,
Dmitrii Derepko.
@xepozz

Reply via email to