Skip to content

Commit

Permalink
Add read-only wrappers for PHP objects; use for PHP user properties.
Browse files Browse the repository at this point in the history
  • Loading branch information
cscott committed Oct 29, 2013
1 parent 81d4418 commit ec8b16f
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 16 deletions.
7 changes: 6 additions & 1 deletion php_v8js_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ typedef v8::Persistent<v8::FunctionTemplate, v8::CopyablePersistentTraits<v8::Fu

/* Hidden field name used to link JS wrappers with underlying PHP object */
#define PHPJS_OBJECT_KEY "phpjs::object"
/* Hidden field name used to enforce read-only wrappers */
#define PHPJS_READONLY_KEY "phpjs::readonly"

/* Helper macros */
#if PHP_V8_API_VERSION < 2005009
Expand Down Expand Up @@ -115,6 +117,9 @@ typedef v8::Persistent<v8::FunctionTemplate, v8::CopyablePersistentTraits<v8::Fu
#define V8JS_FLAG_NONE (1<<0)
#define V8JS_FLAG_FORCE_ARRAY (1<<1)

/* options for V8 object wrappers */
#define V8JS_FLAG_READ_ONLY (1<<2)

#define V8JS_DEBUG_AUTO_BREAK_NEVER 0
#define V8JS_DEBUG_AUTO_BREAK_ONCE 1
#define V8JS_DEBUG_AUTO_BREAK_ALWAYS 2
Expand All @@ -137,7 +142,7 @@ void php_v8js_create_v8(zval *, v8::Handle<v8::Value>, int, v8::Isolate * TSRMLS
int php_v8js_v8_get_properties_hash(v8::Handle<v8::Value>, HashTable *, int, v8::Isolate * TSRMLS_DC);

/* Convert zval into V8 value */
v8::Handle<v8::Value> zval_to_v8js(zval *, v8::Isolate * TSRMLS_DC);
v8::Handle<v8::Value> zval_to_v8js(zval *, int, v8::Isolate * TSRMLS_DC);

/* Convert V8 value into zval */
int v8js_to_zval(v8::Handle<v8::Value>, zval *, int, v8::Isolate * TSRMLS_DC);
Expand Down
6 changes: 3 additions & 3 deletions v8js.cc
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ static void php_v8js_v8_write_property(zval *object, zval *member, zval *value Z
v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj);

if (v8obj->IsObject() && !v8obj->IsFunction()) {
v8obj->ToObject()->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, isolate TSRMLS_CC));
v8obj->ToObject()->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, 0, isolate TSRMLS_CC));
}
}
/* }}} */
Expand Down Expand Up @@ -411,7 +411,7 @@ static int php_v8js_v8_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) /
v8::Local<v8::Value> js_retval;

for (i = 0; i < argc; i++) {
jsArgv[i] = v8::Local<v8::Value>::New(isolate, zval_to_v8js(*argv[i], isolate TSRMLS_CC));
jsArgv[i] = v8::Local<v8::Value>::New(isolate, zval_to_v8js(*argv[i], 0, isolate TSRMLS_CC));
}

js_retval = cb->Call(V8JS_GLOBAL, argc, jsArgv);
Expand Down Expand Up @@ -861,7 +861,7 @@ static PHP_METHOD(V8Js, __construct)
v8::Context::Scope context_scope(context);

/* Create the PHP container object */
v8::Local<v8::Value> php_obj = zval_to_v8js(&c->user_properties, isolate TSRMLS_CC);
v8::Local<v8::Value> php_obj = zval_to_v8js(&c->user_properties, V8JS_FLAG_READ_ONLY, isolate TSRMLS_CC);

/* Set name for the PHP JS object */
v8::Local<v8::String> object_name_js = (object_name_len) ? V8JS_SYML(object_name, object_name_len) : V8JS_SYM("PHP");
Expand Down
30 changes: 18 additions & 12 deletions v8js_convert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ static void php_v8js_call_php_func(zval *value, zend_class_entry *ce, zend_funct
}

if (retval_ptr != NULL) {
return_value = zval_to_v8js(retval_ptr, isolate TSRMLS_CC);
return_value = zval_to_v8js(retval_ptr, 0, isolate TSRMLS_CC);
zval_ptr_dtor(&retval_ptr);
} else {
return_value = V8JS_NULL;
Expand Down Expand Up @@ -572,6 +572,8 @@ static inline v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8
// this is a property (not a method)
name++; name_len--;
}
// access control!
v8::Local<v8::Value> ro = self->GetHiddenValue(V8JS_SYM(PHPJS_READONLY_KEY));
if (callback_type == V8JS_PROP_GETTER) {
/* Nope, not a method -- must be a (case-sensitive) property */
php_value = zend_read_property(scope, object, V8JS_CONST name, name_len, true TSRMLS_CC);
Expand All @@ -582,7 +584,7 @@ static inline v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8
ret_value = v8::Handle<v8::Value>();
} else {
// wrap it
ret_value = zval_to_v8js(php_value, isolate TSRMLS_CC);
ret_value = zval_to_v8js(php_value, ro.IsEmpty() ? 0 : V8JS_FLAG_READ_ONLY, isolate TSRMLS_CC);
/* We don't own the reference to php_value... unless the
* returned refcount was 0, in which case the below code
* will free it. */
Expand All @@ -591,7 +593,7 @@ static inline v8::Local<v8::Value> php_v8js_named_property_callback(v8::Local<v8
}
} else if (callback_type == V8JS_PROP_SETTER) {
MAKE_STD_ZVAL(php_value);
if (v8js_to_zval(set_value, php_value, 0, isolate TSRMLS_CC) == SUCCESS) {
if (ro.IsEmpty() && v8js_to_zval(set_value, php_value, 0, isolate TSRMLS_CC) == SUCCESS) {
zend_update_property(scope, object, V8JS_CONST name, name_len, php_value TSRMLS_CC);
ret_value = set_value;
} else {
Expand Down Expand Up @@ -658,7 +660,7 @@ static void php_v8js_named_property_deleter(v8::Local<v8::String> property, cons
}
/* }}} */

static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, int flags, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
{
v8::Handle<v8::Object> newobj;
int i;
Expand Down Expand Up @@ -753,6 +755,10 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
newobj = new_tpl->InstanceTemplate()->NewInstance();
}

if (flags & V8JS_FLAG_READ_ONLY) {
newobj->SetHiddenValue(V8JS_SYM(PHPJS_READONLY_KEY), V8JS_BOOL(1));
}

/* Object properties */
i = myht ? zend_hash_num_elements(myht) : 0;

Expand Down Expand Up @@ -784,9 +790,9 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
}
continue;
}
newobj->Set(V8JS_STRL(key, key_len - 1), zval_to_v8js(*data, isolate TSRMLS_CC), v8::ReadOnly);
newobj->Set(V8JS_STRL(key, key_len - 1), zval_to_v8js(*data, flags, isolate TSRMLS_CC), v8::ReadOnly);
} else {
newobj->Set(index, zval_to_v8js(*data, isolate TSRMLS_CC));
newobj->Set(index, zval_to_v8js(*data, flags, isolate TSRMLS_CC));
}

if (tmp_ht) {
Expand All @@ -799,14 +805,14 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
}
/* }}} */

static v8::Handle<v8::Value> php_v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
static v8::Handle<v8::Value> php_v8js_hash_to_jsarr(zval *value, int flags, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
{
HashTable *myht = HASH_OF(value);
int i = myht ? zend_hash_num_elements(myht) : 0;

/* Return object if dealing with assoc array */
if (i > 0 && _php_v8js_is_assoc_array(myht TSRMLS_CC)) {
return php_v8js_hash_to_jsobj(value, isolate TSRMLS_CC);
return php_v8js_hash_to_jsobj(value, flags, isolate TSRMLS_CC);
}

v8::Local<v8::Array> newarr;
Expand Down Expand Up @@ -835,7 +841,7 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsarr(zval *value, v8::Isolate *is
tmp_ht->nApplyCount++;
}

newarr->Set(index++, zval_to_v8js(*data, isolate TSRMLS_CC));
newarr->Set(index++, zval_to_v8js(*data, flags, isolate TSRMLS_CC));

if (tmp_ht) {
tmp_ht->nApplyCount--;
Expand All @@ -846,18 +852,18 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsarr(zval *value, v8::Isolate *is
}
/* }}} */

v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
v8::Handle<v8::Value> zval_to_v8js(zval *value, int flags, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
{
v8::Handle<v8::Value> jsValue;

switch (Z_TYPE_P(value))
{
case IS_ARRAY:
jsValue = php_v8js_hash_to_jsarr(value, isolate TSRMLS_CC);
jsValue = php_v8js_hash_to_jsarr(value, flags, isolate TSRMLS_CC);
break;

case IS_OBJECT:
jsValue = php_v8js_hash_to_jsobj(value, isolate TSRMLS_CC);
jsValue = php_v8js_hash_to_jsobj(value, flags, isolate TSRMLS_CC);
break;

case IS_STRING:
Expand Down

0 comments on commit ec8b16f

Please sign in to comment.