From 48a6566f469cc16300232b6faa783d09aa69cdfd Mon Sep 17 00:00:00 2001 From: nsfisis Date: Thu, 23 Jul 2026 22:54:18 +0900 Subject: feat(process-executor): stub plugin-facing execute_async_php path A plugin can reach ProcessExecutor::executeAsync() through the rust-proxy stub, which resolves with a real Symfony Process instance that can't be reconstructed on the Rust side (its state is tied to whichever process calls proc_open(), and it refuses serialization). Add execute_async_php() as a todo!() stub, documented as a dual- instantiation split in plugin-class-classification.md: Rust-internal callers keep using execute_async(), while the plugin path must forward spawning to the PHP child once the RPC channel exists. --- docs/dev/plugin-class-classification.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'docs/dev/plugin-class-classification.md') diff --git a/docs/dev/plugin-class-classification.md b/docs/dev/plugin-class-classification.md index 263161cb..13286248 100644 --- a/docs/dev/plugin-class-classification.md +++ b/docs/dev/plugin-class-classification.md @@ -375,6 +375,21 @@ PHP-locally (or the stub `NewObject` constructor story lands); until the user decides, the tool reports them as `unsupported` with the constructing site named. +### Process: dual instantiation split by caller + +`ProcessExecutor::executeAsync()` resolves its promise with a +`Symfony\Component\Process\Process` instance, so it may cross the language +boundary despite being a wholesale-`php-native` vendor class. A `Process` +can't be reconstructed PHP-side from Rust-generated data because its state +is stored in a `resource` created by `proc_open()`. + +Resolution: split `ProcessExecutor`'s Rust implementation by caller. +Rust-ported Composer code (`VersionGuesser`, `Git`, …) calls `execute_async()` +directly and spawns in Rust. A plugin holding a `ProcessExecutor` handle +(`Loop::getProcessExecutor()`) instead hits the `rust-proxy` stub's RPC entry, +which forwards the spawn to the PHP child so the real `Process::start()` runs +there. The plugin gets the genuine object, never a fake one. + ### Package and CompletePackage They classify as `rust-proxy` mechanically: they carry setters -- cgit v1.3.1