diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-20 09:50:58 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-20 09:50:58 +0900 |
| commit | 94507ec2f265ca9400d64d42036ca1e8722e27da (patch) | |
| tree | fca64359a8d9257717bc41822ae7119bdc3e2b26 /crates/shirabe/src/plugin | |
| parent | 80c2120a64ce9b989da288ce1fcf80dec5cf38c1 (diff) | |
| download | php-shirabe-94507ec2f265ca9400d64d42036ca1e8722e27da.tar.gz php-shirabe-94507ec2f265ca9400d64d42036ca1e8722e27da.tar.zst php-shirabe-94507ec2f265ca9400d64d42036ca1e8722e27da.zip | |
fix(event-dispatcher): let a PHP script reach the Composer object graph
A PHP script listener that walks the event it receives (Laravel's
Illuminate\Foundation\ComposerScripts::postAutoloadDump asks for
$event->getComposer()->getConfig()->get('vendor-dir')) aborted the run
with `unknown Rust handle 2`.
The event's getComposer/getIO answers register an entity in the R table
and hand back its rhandle, but ScriptRpcDispatcher resolved only rhandle
0 and the one event handle of the call in flight, so it could not serve a
method on a handle it had just minted itself. The R-table lookup
PluginRpcDispatcher already does is now dispatch_r_table_method, shared
by both.
The stubs that graph hands out extend and implement the real Composer
contracts (Composer\Package\PackageInterface and the rest), which live in
the Composer PHP runtime and not among the generated stubs or guards, so
execute_event_php_script loads that runtime the way the plugin and
command-class paths do.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/plugin')
| -rw-r--r-- | crates/shirabe/src/plugin/php_plugin_proxy.rs | 93 |
1 files changed, 50 insertions, 43 deletions
diff --git a/crates/shirabe/src/plugin/php_plugin_proxy.rs b/crates/shirabe/src/plugin/php_plugin_proxy.rs index 0cd36b18..9ebdbbff 100644 --- a/crates/shirabe/src/plugin/php_plugin_proxy.rs +++ b/crates/shirabe/src/plugin/php_plugin_proxy.rs @@ -340,52 +340,59 @@ impl RustMethodDispatcher for PluginRpcDispatcher<'_> { return dispatch_event_method(event, method_name); } - // The entity is cloned out so no table borrow is held while the handler runs (a - // handler that re-enters register_*_entity would otherwise panic on the RefCell). - let entity = R_TABLE.with(|table| table.borrow().get(&rhandle).cloned()); - if method_name == "__shirabeClone" { - return match entity { - Some(entity) => clone_entity(&entity), - None => Err(runtime_throw(format!("unknown Rust handle {rhandle}"))), - }; + dispatch_r_table_method(rhandle, method_name, &args) + } +} + +/// Serves a method call on an R-table entity, shared by every dispatcher: the child holds a +/// stub for an entity registered by an earlier call, and the handle outlives the call that +/// minted it. +pub(crate) fn dispatch_r_table_method( + rhandle: u64, + method_name: &str, + args: &[PluginValue], +) -> Result<PluginValue, PhpThrow> { + // The entity is cloned out so no table borrow is held while the handler runs (a + // handler that re-enters register_*_entity would otherwise panic on the RefCell). + let entity = R_TABLE.with(|table| table.borrow().get(&rhandle).cloned()); + if method_name == "__shirabeClone" { + return match entity { + Some(entity) => clone_entity(&entity), + None => Err(runtime_throw(format!("unknown Rust handle {rhandle}"))), + }; + } + if matches!(method_name, "__get" | "__set" | "__isset" | "__unset") { + return match entity { + Some(entity) => dispatch_property_access(&entity, method_name, args), + None => Err(runtime_throw(format!("unknown Rust handle {rhandle}"))), + }; + } + match entity { + Some(RustEntity::Io(io)) => dispatch_io_method(&io, method_name, args), + Some(RustEntity::Composer(composer)) => dispatch_composer_method(&composer, method_name), + Some(RustEntity::Config(config)) => dispatch_config_method(&config, method_name, args), + Some(RustEntity::DownloadManager(dm)) => { + dispatch_download_manager_method(&dm, method_name, args) } - if matches!(method_name, "__get" | "__set" | "__isset" | "__unset") { - return match entity { - Some(entity) => dispatch_property_access(&entity, method_name, &args), - None => Err(runtime_throw(format!("unknown Rust handle {rhandle}"))), - }; + Some(RustEntity::Filesystem(fs)) => dispatch_filesystem_method(&fs, method_name, args), + Some(RustEntity::InstallationManager(im)) => { + dispatch_installation_manager_method(&im, method_name, args) } - match entity { - Some(RustEntity::Io(io)) => dispatch_io_method(&io, method_name, &args), - Some(RustEntity::Composer(composer)) => { - dispatch_composer_method(&composer, method_name) - } - Some(RustEntity::Config(config)) => dispatch_config_method(&config, method_name, &args), - Some(RustEntity::DownloadManager(dm)) => { - dispatch_download_manager_method(&dm, method_name, &args) - } - Some(RustEntity::Filesystem(fs)) => dispatch_filesystem_method(&fs, method_name, &args), - Some(RustEntity::InstallationManager(im)) => { - dispatch_installation_manager_method(&im, method_name, &args) - } - Some(RustEntity::RepositoryManager(rm)) => { - dispatch_repository_manager_method(&rm, method_name) - } - Some(RustEntity::Repository(repository)) => { - dispatch_repository_method(&repository, method_name, &args) - } - Some(RustEntity::Package(package)) => { - dispatch_package_method(&package, method_name, &args) - } - Some(RustEntity::EventDispatcher(dispatcher)) => { - dispatch_event_dispatcher_method(&dispatcher, method_name, &args) - } - Some(RustEntity::Operation(operation)) => { - dispatch_operation_method(&operation, method_name, &args) - } - Some(RustEntity::Plugin(plugin)) => dispatch_plugin_method(&plugin, method_name), - None => Err(runtime_throw(format!("unknown Rust handle {rhandle}"))), + Some(RustEntity::RepositoryManager(rm)) => { + dispatch_repository_manager_method(&rm, method_name) + } + Some(RustEntity::Repository(repository)) => { + dispatch_repository_method(&repository, method_name, args) + } + Some(RustEntity::Package(package)) => dispatch_package_method(&package, method_name, args), + Some(RustEntity::EventDispatcher(dispatcher)) => { + dispatch_event_dispatcher_method(&dispatcher, method_name, args) + } + Some(RustEntity::Operation(operation)) => { + dispatch_operation_method(&operation, method_name, args) } + Some(RustEntity::Plugin(plugin)) => dispatch_plugin_method(&plugin, method_name), + None => Err(runtime_throw(format!("unknown Rust handle {rhandle}"))), } } |
