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