phpv8 / v8js

V8 Javascript Engine for PHP — This PHP extension embeds the Google V8 Javascript Engine
http://pecl.php.net/package/v8js
MIT License
1.84k stars 200 forks source link

Promise support #208

Closed stesie closed 8 years ago

stesie commented 8 years ago

Promises are an increasingly popular topic in JS world, and V8 supports ES6 promises well since quite a few releases

Passing Promise instances from JS to PHP should already work by normal wrapping means, i.e. V8Object. This is PHP can register methods via then and catch as needed, which are wrapped to V8 native functions like usual.

Creating promises is more involved, either you ship a promise implementation on PHP side ... then normal existing wrapping means can be used. Or you need a JS-side "factory" that does the instanciation.

$v8 = new V8Js();
$promiseFactory = $v8->executeString(<<<EOF
(function _promiseFactory($resolver) {
  return new Promise($resolver);
});

that would allow you to

$promise = $promiseFactory(function($resolve, $reject) {
  // either sync or async implementation of the promise here
  $resolve('the_result');
});
return $promise;  // whatever ...

... the whole $promiseFactory is implicitly bound to $v8 as it actually is just a plain V8Object.

V8Js could provide some V8Promise class, which might try to mimic JS' new Promise syntax like

$promise = new V8Promise(function($resolve, $reject) {
  ....
});
return $promise; // ... pass $promise back to JS

... this initially does not bind the V8Promise to a V8 instance, which is kindof bad. The straight forward option would be to add a \V8Js reference as first argument to the V8Promise::__construct constructor method. This would allow even PHP code to immediately call then and catch to register own handlers.

Another, more magic, option would be to implicitly bind the V8Promise to a V8 instance once it is passed to V8. However that way then and catch won't be usable until passed back to V8 -- and in the end we might need some explicit bind.

What do you think? Should V8Js provide a V8Promise class? Which signature?

stesie commented 8 years ago

my personal favourite would be to provide a V8Promise class behaving exactly like V8Object yet providing a V8Promise::__construct(\V8Js $v8, Callable $resolver) signature.

Besides wrapping JavaScript/ES6 Promise objects to V8Promise class instead of V8Object to aid type-hinting in V8.

This could very well be fleshed out to a static V8Js::createWrapperClass(string $phpClassName, string $jsPrototypeName) method, that constructs aforesaid "trampoline". That is a \V8Js::createWrapperClass("V8Promise", "Promise") would on-the-fly create the V8Promise class above. Yet this requires run-time creation of PHP classes from C-Code side. I'm uncertain if (and how clean) this is possible.

stesie commented 8 years ago

There are other methods like Promise.resolve that might be useful as well, hence the simple wrapper class might very well be way too simple :-)

At https://stesie.github.io/2016/03/V8PromiseFactory I blogged about implementing a simple V8PromiseFactory as in the initial post here (just as a full-fledged class). It's not long and it can do everything on PHP-side which the extension can do on the C-code side (but way harder to write and more errorprone).

If such a class (or others) really turn out to be useful we're IMHO better off to publish a v8js-extras package on packagist.org ... therefore self-closing this issue now.