mirror of
https://github.com/phpv8/v8js.git
synced 2024-11-09 16:28:41 +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:
parent
02d8ecc16e
commit
2b897e8bc4
62
tests/array_access_003.phpt
Normal file
62
tests/array_access_003.phpt
Normal 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===
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user