diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-07 05:11:55 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-07 05:11:55 +0900 |
| commit | 9a393adc0ace86cac788723b524e83c63dfc91c1 (patch) | |
| tree | fadac10efa6518c1a5d4d16f829da6969229ce09 /crates/shirabe-php-rpc/php/worker.php | |
| parent | 14a8a474120ef4289625f05ba5d87fa9e9d19542 (diff) | |
| download | php-shirabe-9a393adc0ace86cac788723b524e83c63dfc91c1.tar.gz php-shirabe-9a393adc0ace86cac788723b524e83c63dfc91c1.tar.zst php-shirabe-9a393adc0ace86cac788723b524e83c63dfc91c1.zip | |
feat(php-rpc): cross materialized values as PHP object records
A materialized value used to cross as a constructor call: the class name,
the arguments, and any post-construction setter. Describing a real
instance that way needed a ReflectionProperty read for every field the
class exposes no getter for, and state no constructor takes (an unset
pretty string, a Link built without a pretty constraint) had no faithful
call to describe it at all.
The value now crosses as the object record serialize() writes for it,
which unserialize() revives without running a constructor, so both sides
transfer the state itself instead of a recipe for rebuilding it. The PHP
half keeps only the class list (also the allowed_classes list of every
frame payload) and the UTC rebasing of dates; describe(), build() and the
reflection are gone.
The wire codec gains O: records (PluginValue::PhpObject) and r: back
references, whose resolution reproduces PHP's numbering of every value in
a payload; a cyclic object graph and a PHP reference (R:) are rejected.
Two behaviours change with it: a date crosses carrying timezone_type 3
"UTC" rather than a +00:00 offset, which is what ArrayLoader builds a
release date as, and a Link subclass crosses as a P-table entity instead
of being silently downgraded to a plain Link.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-php-rpc/php/worker.php')
| -rw-r--r-- | crates/shirabe-php-rpc/php/worker.php | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/crates/shirabe-php-rpc/php/worker.php b/crates/shirabe-php-rpc/php/worker.php index 092f535f..15b38770 100644 --- a/crates/shirabe-php-rpc/php/worker.php +++ b/crates/shirabe-php-rpc/php/worker.php @@ -227,9 +227,11 @@ final class ShirabeRpcRuntime // A natively-constructed dual-mode instance falls through to the P table below. } if (is_object($value)) { - $materialized = \Shirabe\MaterializedValue::describe($value); + // A materialized value needs no descriptor: it crosses as the object record + // serialize() writes for it, which the Rust side decodes into its own value. + $materialized = \Shirabe\MaterializedValue::forWire($value); if ($materialized !== null) { - return array_map([self::class, 'toWire'], $materialized); + return $materialized; } return ShirabePhpObjectRegistry::descriptor($value); } @@ -242,7 +244,10 @@ final class ShirabeRpcRuntime return $value; } - /** Converts a decoded wire value: handle descriptor arrays become live objects. */ + /** + * Converts a decoded wire value: handle descriptor arrays become live objects. A + * materialized value arrives as a real instance already, revived by unserialize(). + */ public static function fromWire($value) { if (!is_array($value)) { @@ -261,9 +266,6 @@ final class ShirabeRpcRuntime if (isset($value['__pclass']) && count($value) === 1) { return $value['__pclass']; } - if (isset($value['__pnew'])) { - return \Shirabe\MaterializedValue::build(array_map([self::class, 'fromWire'], $value)); - } return array_map([self::class, 'fromWire'], $value); } @@ -287,7 +289,7 @@ final class ShirabeRpcRuntime if ($inId !== $corrId) { self::fail("protocol violation: response for unexpected corr_id {$inId}"); } - $fields = unserialize($payload, ['allowed_classes' => false]); + $fields = unserialize($payload, ['allowed_classes' => \Shirabe\MaterializedValue::CLASSES]); if (!is_array($fields)) { self::fail('protocol violation: unparseable response payload'); } @@ -314,7 +316,7 @@ final class ShirabeRpcRuntime public static function dispatchRequest(int $tag, int $corrId, string $payload): void { - $fields = unserialize($payload, ['allowed_classes' => false]); + $fields = unserialize($payload, ['allowed_classes' => \Shirabe\MaterializedValue::CLASSES]); if (!is_array($fields)) { self::fail('protocol violation: unparseable frame payload'); } @@ -588,7 +590,9 @@ ShirabeRpcRuntime::$dispatch = [ // Shirabe-internal helpers, not PHP builtins: '__shirabe_eval' => static fn($args) => eval($args[0]), // Round-trips raw serialize() bytes through the PHP core codec, for the codec oracle tests. - '__shirabe_oracle_roundtrip' => static fn($args) => serialize(unserialize($args[0], ['allowed_classes' => false])), + '__shirabe_oracle_roundtrip' => static fn($args) => serialize( + unserialize($args[0], ['allowed_classes' => \Shirabe\MaterializedValue::CLASSES]) + ), '__shirabe_require' => static function ($args) { require_once $args[0]; // The required file may have registered further prepending autoloaders (a Composer |
