diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/plugin-stub-generator/src/Generator.php | 31 |
1 files changed, 13 insertions, 18 deletions
diff --git a/scripts/plugin-stub-generator/src/Generator.php b/scripts/plugin-stub-generator/src/Generator.php index 1e41eed8..ce8f612b 100644 --- a/scripts/plugin-stub-generator/src/Generator.php +++ b/scripts/plugin-stub-generator/src/Generator.php @@ -50,6 +50,16 @@ final class Generator '__epoch' => $this->__epoch, ]; } + + public function __clone() + { + // PHP has already shallow-copied this stub, so both copies would point at one + // entity and release it twice. The Rust side clones the entity instead, applying + // whatever __clone semantics the real class defines, and this copy rebinds to the + // fresh handle. Entities without clone semantics answer with an explicit error. + [$this->__rhandle, $this->__epoch] = \ShirabeRpcRuntime::callRust($this->__rhandle, '__shirabeClone', []); + \ShirabeRustObjectRegistry::adopt($this->__rhandle, $this); + } PHP; private const PROPERTY_FORWARDERS = <<<'PHP' @@ -65,15 +75,6 @@ final class Generator } PHP; - private const CLONE_THROW = <<<'PHP' - public function __clone() - { - // Cloning a proxy is an open design question; fail instead of silently sharing - // the Rust-side entity between two stub instances. - throw new \RuntimeException('Shirabe does not support cloning ' . static::class . ' inside the plugin process yet'); - } - PHP; - private Project $project; private NamePrinter $printer; @@ -234,7 +235,6 @@ final class Generator $publicStatics = []; $nonPublicStatics = []; $ownInstanceMethods = []; - $cloneThrows = false; foreach ($class->getMethods() as $method) { $name = $method->name->toString(); if ($name === '__construct') { @@ -245,14 +245,12 @@ final class Generator $this->errors[] = "$fqcn::$name: magic methods cannot be proxied"; } // __toString is an ordinary zero-argument call under a magic name and is - // forwarded below; __clone semantics are an open design question and the - // emitted body throws instead of silently sharing the Rust handle. + // forwarded below. A real __clone declaration needs no counterpart here: the + // boilerplate's forwarder delegates cloning to the entity, whose Rust-side + // clone carries the declared semantics. if ($method->isPublic() && $name === '__toString') { $ownInstanceMethods[$name] = $method; } - if ($method->isPublic() && $name === '__clone') { - $cloneThrows = true; - } continue; } if ($method->isStatic()) { @@ -343,9 +341,6 @@ final class Generator if ($hasPublicInstanceProperties) { $members[] = self::PROPERTY_FORWARDERS; } - if ($cloneThrows) { - $members[] = self::CLONE_THROW; - } $members = array_merge($members, $staticMethods, $methodTexts); $body = implode("\n\n", $members); |
