aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-php-rpc/src/lib.rs
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 /crates/shirabe-php-rpc/src/lib.rs
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 'crates/shirabe-php-rpc/src/lib.rs')
-rw-r--r--crates/shirabe-php-rpc/src/lib.rs17
1 files changed, 17 insertions, 0 deletions
diff --git a/crates/shirabe-php-rpc/src/lib.rs b/crates/shirabe-php-rpc/src/lib.rs
index dfd8fa67..c898fb82 100644
--- a/crates/shirabe-php-rpc/src/lib.rs
+++ b/crates/shirabe-php-rpc/src/lib.rs
@@ -621,6 +621,15 @@ pub struct PhpThrow {
pub exception_class: String,
pub message: String,
pub code: i64,
+ /// The state the exception carries beyond `message` and `code`, keyed by the property names
+ /// its class declares. The child revives them onto the instance it rebuilds.
+ ///
+ /// TODO(plugin): populated only Rust to PHP. An exception a plugin throws crosses with its
+ /// class, message and code alone, because no Rust-side consumer rebuilds a ported exception
+ /// from a `PhpThrow` yet.
+ ///
+ /// Boxed so a `Result<_, PhpThrow>` stays small; every dispatcher returns one.
+ pub properties: Box<IndexMap<String, PluginValue>>,
}
impl PhpThrow {
@@ -629,6 +638,7 @@ impl PhpThrow {
exception_class: "RuntimeException".to_string(),
message,
code: 0,
+ properties: Box::new(IndexMap::new()),
}
}
}
@@ -805,11 +815,13 @@ fn rpc_call(
exception_class,
message,
code,
+ properties,
} if corr_id == my_id => {
return Ok(Err(PhpThrow {
exception_class,
message,
code,
+ properties: Box::new(properties),
}));
}
Frame::CallRustMethod {
@@ -846,6 +858,7 @@ fn rpc_call(
exception_class: throw.exception_class,
message: throw.message,
code: throw.code,
+ properties: *throw.properties,
},
};
send_frame(&reply)?;
@@ -1042,6 +1055,10 @@ const RUNTIME_FILES: &[(&str, &str)] = &[
include_str!("../php/runtime/Composer/EventDispatcher/Event.php"),
),
(
+ "Shirabe/MaterializedThrowable.php",
+ include_str!("../php/runtime/Shirabe/MaterializedThrowable.php"),
+ ),
+ (
"Shirabe/MaterializedValue.php",
include_str!("../php/runtime/Shirabe/MaterializedValue.php"),
),