diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-30 23:01:25 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-30 23:09:56 +0900 |
| commit | d3bc3354c9705dfc6dc5e9b9adb5eb64d41e4c49 (patch) | |
| tree | a745ecc3403104d5a34f29964362e239e8f5675b /crates/shirabe/src/event_dispatcher | |
| parent | 057f3b8de26293319e265c1d86d9a1153124f3c7 (diff) | |
| download | php-shirabe-d3bc3354c9705dfc6dc5e9b9adb5eb64d41e4c49.tar.gz php-shirabe-d3bc3354c9705dfc6dc5e9b9adb5eb64d41e4c49.tar.zst php-shirabe-d3bc3354c9705dfc6dc5e9b9adb5eb64d41e4c49.zip | |
feat(plugin): serve ProcessExecutor as a proxy stub
Composer reaches this class two ways: the object graph hands one out through
Composer::getLoop()->getProcessExecutor(), and plugins write
`new ProcessExecutor($io)` freely. Both bind to a Rust-side entity, so the
timeout the run shares -- seeded from process-timeout and rewritten while the
run is in flight -- has one value instead of one per world, and the executor
can still be passed to the classes that take one (`new Filesystem($process)`).
Three things the stub generator was missing came with it:
- By-ref parameters. The call carries their positions and the answer carries
what each holds afterwards; a position the answer omits was never assigned
to, which is what PHP does with an untouched by-ref parameter.
ProcessExecutor::execute is the only one on a proxied class.
- Argument arity, reproduced where the real body reads func_num_args().
execute($cmd) forwards the child's output and execute($cmd, $out) captures
it, and nothing but the argument count separates the two.
- Static methods that cannot run in the worker. One that reads a static
property the Rust side owns, or that reaches a guarded class, forwards
through __shirabeCallStatic instead of being materialized. That also fixes
Filesystem::isLocalPath and getPlatformPath, whose materialized bodies
called the guarded Composer\Util\Platform.
The async surface stays an explicit error. executeAsync resolves its promise
with a Symfony Process, whose proc_open() resource and pipes belong to
whichever process called start(), so a Rust-side spawn has none to hand back;
running the real start() in the worker needs a promise representation that
crosses the boundary unresolved.
The fixture project drives the whole synchronous surface from plugin code and
compares the trace against upstream Composer byte for byte.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/event_dispatcher')
| -rw-r--r-- | crates/shirabe/src/event_dispatcher/event_dispatcher.rs | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs index a5a238bd..7b620e5b 100644 --- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs +++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs @@ -1682,6 +1682,7 @@ impl RustMethodDispatcher for ScriptRpcDispatcher<'_> { method_name: &str, args: Vec<PluginValue>, _out_param_positions: &[u32], + out_params: &mut IndexMap<u32, PluginValue>, ) -> Result<PluginValue, PhpThrow> { if rhandle == 0 { if method_name == "__shirabe_find_file" { @@ -1707,6 +1708,9 @@ impl RustMethodDispatcher for ScriptRpcDispatcher<'_> { if method_name == "__shirabeConstruct" { return crate::plugin::php_plugin_proxy::construct_entity(&args); } + if method_name == "__shirabeCallStatic" { + return crate::plugin::php_plugin_proxy::call_static_entity(&args); + } return Err(runtime_throw(format!( "unknown runtime service method `{method_name}`" ))); @@ -1719,6 +1723,7 @@ impl RustMethodDispatcher for ScriptRpcDispatcher<'_> { rhandle, method_name, &args, + out_params, ), } } |
