aboutsummaryrefslogtreecommitdiffhomepage
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/plugin-stub-generator/src/Generator.php31
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);