共享对象
目前不支持将 PHP 对象按引用传给 JavaScript,以读取其属性、调用其方法并查看 PHP 中的变化。此问题正在 问题 #18 中跟踪。本页介绍当前的行为以及可用的替代模式。
当前行为
setGlobal() 会按照 值转换 中的规则转换其值。不可调用的 PHP 对象没有对应的转换,因此该全局值为 undefined:
PHP
class Counter {
public int $value = 0;
public function increment(): void { $this->value++; }
}
$counter = new Counter();
$engine->setGlobal('counter', $counter);
$engine->eval('typeof counter');
// "undefined"
$engine->eval('counter.increment()');
// throws Phasis\Exceptions\TypeError:
// Cannot read properties of undefined (reading 'increment')
stdClass、实体和模型、服务容器、生成器及资源也同样如此。有两种例外是可调用对象:
- 带有
__invoke()的对象会变成调用该对象的 JS 函数。 - 可调用数组(例如
[$counter, 'increment'])会变成调用该方法的 JS 函数。
没有 PhpBridge 或其他用于暴露对象的包装类;src/Interop/ 只包含值转换器。
将方法暴露为闭包
闭包可以捕获对象,因此 JS 调用函数时,方法会在原始的 PHP 实例上运行:
PHP
$counter = new Counter();
$engine->setGlobal('increment', fn () => $counter->increment());
$engine->setGlobal('count', fn () => $counter->value);
$engine->eval('increment(); increment(); count()');
// 2
echo $counter->value;
// 2
可调用数组无需闭包,也能实现相同效果:
PHP
$engine->setGlobal('increment', [$counter, 'increment']);
将它们分组到数组中
关联数组会变成 JS 对象,其中的闭包会变成函数。这样就为 JS 提供了形似对象的 API,其方法会作用于 PHP 实例:
PHP
class User {
public function __construct(
public string $name,
public int $age,
private string $secret,
) {}
public function greet(): string {
return "Hi, I'm $this->name";
}
}
$user = new User('Ada', 36, 'topsecret');
$engine->setGlobal('user', [
'name' => $user->name,
'greet' => fn () => $user->greet(),
'setAge' => function (int $age) use ($user): void { $user->age = $age; },
]);
$engine->eval('user.greet()');
// "Hi, I'm Ada"
$engine->eval('user.setAge(37)');
echo $user->age;
// 37
只有放入数组中的内容才会对 JS 可见,因此 $secret 等私有状态仍保留在 PHP 中。
数据字段会在 setGlobal() 运行时复制。在示例中,user.name 是 JS 中的字符串;对它赋值只会更改 JS 副本,不会更改 $user->name。请通过闭包完成所有写入操作。
传出数据,再传回结果
对于数据形状的对象,在传入时将其转换为数组,并在取回结果时读取:
PHP
$post = ['title' => 'Draft', 'tags' => ['php']];
$engine->setGlobal('post', $post);
$engine->eval('function edit(p) { p.title = "Edited from JS"; return p; }');
$post = $engine->call('edit', $post);
echo $post['title'];
// Edited from JS
get_object_vars($object) 或 toArray() 方法可为对象返回数组。然后在 PHP 中将返回的数组应用到对象、实体或模型上。