0
0
mirror of https://github.com/phpv8/v8js.git synced 2024-09-19 00:25:18 +00:00

Export extra methods on ArrayAccess

This merges the distinct code path for the export of ArrayAccess
capable PHP objects back into the "common" PHP object export code.
Sole difference is that the ArrayAccess-style object has index
property handlers as well as property bridging to Array.prototype.
This commit is contained in:
Stefan Siegl 2014-11-29 20:35:32 +01:00
parent 02d8ecc16e
commit 2b897e8bc4
5 changed files with 147 additions and 47 deletions

View File

@ -0,0 +1,62 @@
--TEST--
Test V8::executeString() : Export PHP methods on ArrayAccess objects
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
--INI--
v8js.use_array_access = 1
--FILE--
<?php
class MyArray implements ArrayAccess, Countable {
private $data = Array('one', 'two', 'three');
public function offsetExists($offset) {
return isset($this->data[$offset]);
}
public function offsetGet($offset) {
return $this->data[$offset];
}
public function offsetSet($offset, $value) {
echo "set[$offset] = $value\n";
$this->data[$offset] = $value;
}
public function offsetUnset($offset) {
throw new Exception('Not implemented');
}
public function count() {
echo 'count() = ', count($this->data), "\n";
return count($this->data);
}
public function phpSidePush($value) {
echo "push << $value\n";
$this->data[] = $value;
}
}
$v8 = new V8Js();
$v8->myarr = new MyArray();
/* Call PHP method to modify the array. */
$v8->executeString('PHP.myarr.phpSidePush(23);');
var_dump(count($v8->myarr));
var_dump($v8->myarr[3]);
/* And JS should see the changes due to live binding. */
$v8->executeString('var_dump(PHP.myarr.join(","));');
?>
===EOF===
--EXPECT--
push << 23
count() = 4
int(4)
int(23)
count() = 4
string(16) "one,two,three,23"
===EOF===

View File

@ -24,8 +24,9 @@ extern "C" {
#include "php_v8js_macros.h"
#include "v8js_array_access.h"
#include "v8js_object_export.h"
static void php_v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
void php_v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
{
v8::Isolate *isolate = info.GetIsolate();
v8::Local<v8::Object> self = info.Holder();
@ -71,8 +72,8 @@ static void php_v8js_array_access_getter(uint32_t index, const v8::PropertyCallb
}
/* }}} */
static void php_v8js_array_access_setter(uint32_t index, v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
void php_v8js_array_access_setter(uint32_t index, v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
{
v8::Isolate *isolate = info.GetIsolate();
v8::Local<v8::Object> self = info.Holder();
@ -130,7 +131,7 @@ static void php_v8js_array_access_setter(uint32_t index, v8::Local<v8::Value> va
}
/* }}} */
static void php_v8js_array_access_length(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
void php_v8js_array_access_length(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
{
v8::Isolate *isolate = info.GetIsolate();
v8::Local<v8::Object> self = info.Holder();
@ -169,26 +170,35 @@ static void php_v8js_array_access_length(v8::Local<v8::String> property, const v
}
/* }}} */
v8::Handle<v8::Value> php_v8js_array_access_to_jsobj(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
void php_v8js_array_access_named_getter(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value> &info) /* {{{ */
{
v8::Local<v8::ObjectTemplate> inst_tpl = v8::ObjectTemplate::New(isolate);
inst_tpl->SetIndexedPropertyHandler(php_v8js_array_access_getter,
php_v8js_array_access_setter);
inst_tpl->SetAccessor(V8JS_STR("length"), php_v8js_array_access_length);
v8::String::Utf8Value cstr(property);
const char *name = ToCString(cstr);
v8::Handle<v8::Object> newobj = inst_tpl->NewInstance();
newobj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), v8::External::New(isolate, value));
if(strcmp(name, "length") == 0) {
php_v8js_array_access_length(property, info);
return;
}
/* Change prototype of `newobj' to that of Array */
v8::Local<v8::Array> arr = v8::Array::New(isolate);
newobj->SetPrototype(arr->GetPrototype());
v8::Local<v8::Value> ret_value = php_v8js_named_property_callback(property, info, V8JS_PROP_GETTER);
return newobj;
if(ret_value.IsEmpty()) {
v8::Isolate *isolate = info.GetIsolate();
v8::Local<v8::Array> arr = v8::Array::New(isolate);
v8::Local<v8::Value> prototype = arr->GetPrototype();
if(!prototype->IsObject()) {
/* ehh? Array.prototype not an object? strange, stop. */
info.GetReturnValue().Set(ret_value);
}
ret_value = prototype->ToObject()->Get(property);
}
info.GetReturnValue().Set(ret_value);
}
/* }}} */
/*
* Local variables:
* tab-width: 4

View File

@ -13,6 +13,16 @@
#ifndef V8JS_ARRAY_ACCESS_H
#define V8JS_ARRAY_ACCESS_H
v8::Handle<v8::Value> php_v8js_array_access_to_jsobj(zval *value, v8::Isolate *isolate TSRMLS_DC);
/* Indexed Property Handlers */
void php_v8js_array_access_getter(uint32_t index,
const v8::PropertyCallbackInfo<v8::Value>& info);
void php_v8js_array_access_setter(uint32_t index, v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<v8::Value>& info);
void php_v8js_array_access_length(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info);
/* Named Property Handlers */
void php_v8js_array_access_named_getter(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value> &info);
#endif /* V8JS_ARRAY_ACCESS_H */

View File

@ -582,16 +582,9 @@ static void php_v8js_fake_call_impl(const v8::FunctionCallbackInfo<v8::Value>& i
}
/* }}} */
typedef enum {
V8JS_PROP_GETTER,
V8JS_PROP_SETTER,
V8JS_PROP_QUERY,
V8JS_PROP_DELETER
} property_op_t;
/* This method handles named property and method get/set/query/delete. */
template<typename T>
static inline v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<T> &info, property_op_t callback_type, v8::Local<v8::Value> set_value = v8::Local<v8::Value>()) /* {{{ */
inline v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<T> &info, property_op_t callback_type, v8::Local<v8::Value> set_value = v8::Local<v8::Value>()) /* {{{ */
{
v8::Isolate *isolate = info.GetIsolate();
v8::String::Utf8Value cstr(property);
@ -870,9 +863,39 @@ static v8::Handle<v8::Object> php_v8js_wrap_object(v8::Isolate *isolate, zend_cl
persist_tpl_ = &ctx->template_cache[ce->name];
persist_tpl_->Reset(isolate, new_tpl);
/* We'll free persist_tpl_ when template_cache is destroyed */
v8::Local<v8::ObjectTemplate> inst_tpl = new_tpl->InstanceTemplate();
v8::NamedPropertyGetterCallback getter = php_v8js_named_property_getter;
/* Check for ArrayAccess object */
if (V8JSG(use_array_access) && ce) {
bool has_array_access = false;
bool has_countable = false;
for (int i = 0; i < ce->num_interfaces; i ++) {
if (strcmp (ce->interfaces[i]->name, "ArrayAccess") == 0) {
has_array_access = true;
}
else if (strcmp (ce->interfaces[i]->name, "Countable") == 0) {
has_countable = true;
}
}
if(has_array_access && has_countable) {
inst_tpl->SetIndexedPropertyHandler(php_v8js_array_access_getter,
php_v8js_array_access_setter);
/* Switch to special ArrayAccess getter, which falls back to
* php_v8js_named_property_getter, but possibly bridges the
* call to Array.prototype functions. */
getter = php_v8js_array_access_named_getter;
}
}
// Finish setup of new_tpl
new_tpl->InstanceTemplate()->SetNamedPropertyHandler
(php_v8js_named_property_getter, /* getter */
inst_tpl->SetNamedPropertyHandler
(getter, /* getter */
php_v8js_named_property_setter, /* setter */
php_v8js_named_property_query, /* query */
php_v8js_named_property_deleter, /* deleter */
@ -991,25 +1014,6 @@ v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate T
return V8JS_NULL;
}
/* Check for ArrayAccess object */
if (V8JSG(use_array_access) && ce) {
bool has_array_access = false;
bool has_countable = false;
for (int i = 0; i < ce->num_interfaces; i ++) {
if (strcmp (ce->interfaces[i]->name, "ArrayAccess") == 0) {
has_array_access = true;
}
else if (strcmp (ce->interfaces[i]->name, "Countable") == 0) {
has_countable = true;
}
}
if(has_array_access && has_countable) {
return php_v8js_array_access_to_jsobj(value, isolate TSRMLS_CC);
}
}
/* Special case, passing back object originating from JS to JS */
if (ce == php_ce_v8_function) {
php_v8js_object *c = (php_v8js_object *) zend_object_store_get_object(value TSRMLS_CC);

View File

@ -16,4 +16,18 @@
v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate TSRMLS_DC);
typedef enum {
V8JS_PROP_GETTER,
V8JS_PROP_SETTER,
V8JS_PROP_QUERY,
V8JS_PROP_DELETER
} property_op_t;
template<typename T>
v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<T> &info,
property_op_t callback_type,
v8::Local<v8::Value> set_value = v8::Local<v8::Value>());
#endif /* V8JS_OBJECT_EXPORT_H */