aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-30 23:57:25 +0900
committernsfisis <nsfisis@gmail.com>2026-08-30 23:57:25 +0900
commita38ed045e9981664d90c05ab43ab4ab6026eb31b (patch)
tree537dbd660882e9af7eec9ddcb7abee4c8aae6e1a /docs
parentd3bc3354c9705dfc6dc5e9b9adb5eb64d41e4c49 (diff)
downloadphp-shirabe-a38ed045e9981664d90c05ab43ab4ab6026eb31b.tar.gz
php-shirabe-a38ed045e9981664d90c05ab43ab4ab6026eb31b.tar.zst
php-shirabe-a38ed045e9981664d90c05ab43ab4ab6026eb31b.zip
feat(plugin): carry an exception's class and state across the boundary
A Rust-side failure reached plugin code as a RuntimeException whose message carried the name of the call that failed, so `catch (TransportException $e)` never matched and the status code the plugin branches on was gone. The Throw frame now names the class the exception was thrown as and carries the state that class declares beyond message and code. \Shirabe\MaterializedThrowable rebuilds it in the child: `new $class($message, $code)` for a class whose constructor has \Exception's shape, then the properties by reflection. A class the child cannot build that way keeps the RuntimeException shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/dev/php-rpc.md10
1 files changed, 9 insertions, 1 deletions
diff --git a/docs/dev/php-rpc.md b/docs/dev/php-rpc.md
index aebf0097..6aa1d737 100644
--- a/docs/dev/php-rpc.md
+++ b/docs/dev/php-rpc.md
@@ -51,7 +51,7 @@ frame is a fatal channel error, not an allocation attempt.
| `0x03` | `CallPhpMethod` | Rust→PHP | `phandle`, `method_name`, `args`, `out_param_positions` |
| `0x04` | `CallRustMethod` | PHP→Rust | `rhandle`, `method_name`, `args`, `out_param_positions` |
| `0x05` | `Return` | both | `value`, `out_params` |
-| `0x06` | `Throw` | both | `exception_class`, `message`, `code` |
+| `0x06` | `Throw` | both | `exception_class`, `message`, `code`, `properties` |
| `0x07` | `ReleaseRustHandle` | PHP→Rust | `rhandle` |
| `0x08` | `ReleasePhpHandle` | Rust→PHP | `phandle` |
| `0x09` | `EpochBump` | Rust→PHP | `rhandle`, `epoch` |
@@ -123,6 +123,14 @@ same dispatch while waiting for its own `Return`.
frames.
- The inner `Result<PluginValue, PhpThrow>` is the recoverable lane: a PHP exception crossing
the boundary as a `Throw` frame.
+- A `Throw` names the class the exception was thrown as, and `properties` carries the state that
+ class declares beyond `message` and `code`. Rust to PHP, `\Shirabe\MaterializedThrowable`
+ rebuilds the exception in the child — `new $class($message, $code)` for a class whose
+ constructor has `\Exception`'s shape, then the properties by reflection — so a plugin's
+ `catch (TransportException $e)` catches what it would catch under Composer and reads the
+ status code off it. A class the child cannot construct that way keeps the `RuntimeException`
+ shape. PHP to Rust the field is empty: nothing on the Rust side rebuilds a ported exception
+ from a `PhpThrow` yet.
- A frame that decodes to something protocol-invalid is a bug in Shirabe itself (both halves
ship in the same commit) and panics; the PHP side symmetrically dies so Rust observes EOF.
- The legacy scalar query API (`get_php_version` etc.) keeps its historical contract: every