@@ -23,8 +23,26 @@ zend_class_entry *php_ce_jsobject;
2323/* Object Handlers */
2424static zend_object_handlers node_php_jsobject_handlers;
2525
26+ /* Helpful macros for common tasks in PHP magic methods. */
27+
28+ #define PARSE_PARAMS (method, ...) \
29+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, __VA_ARGS__) == FAILURE) { \
30+ zend_throw_exception (zend_exception_get_default (TSRMLS_C), " bad args to " #method, 0 TSRMLS_CC); \
31+ return ; \
32+ } \
33+ node_php_jsobject *obj = (node_php_jsobject *) \
34+ zend_object_store_get_object (this_ptr TSRMLS_CC)
35+
36+ #define THROW_IF_EXCEPTION (...) \
37+ do { if (msg.HasException ()) { \
38+ zend_throw_exception_ex ( \
39+ zend_exception_get_default (TSRMLS_C), 0 TSRMLS_CC, \
40+ __VA_ARGS__); \
41+ return ; \
42+ } } while (0 )
2643
2744/* JsObject handlers */
45+
2846class JsHasPropertyMsg : public MessageToJs {
2947 Value object_;
3048 Value member_;
@@ -87,26 +105,13 @@ class JsHasPropertyMsg : public MessageToJs {
87105
88106PHP_METHOD (JsObject, __isset) {
89107 zval *member;
90- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, " z/" , &member) == FAILURE) {
91- zend_throw_exception (
92- zend_exception_get_default (TSRMLS_C),
93- " bad property name for __isset" , 0 TSRMLS_CC);
94- return ;
95- }
108+ PARSE_PARAMS (__isset, " z/" , &member);
96109 convert_to_string (member);
97- node_php_jsobject *obj = (node_php_jsobject *)
98- zend_object_store_get_object (this_ptr TSRMLS_CC);
99110 JsHasPropertyMsg msg (obj->channel , obj->id , member, 0 );
100111 obj->channel ->Send (&msg);
101112 msg.WaitForResponse ();
102- // ok, result is in msg.retval_ or msg.exception_
103- if (msg.HasException ()) {
104- zend_throw_exception_ex (
105- zend_exception_get_default (TSRMLS_C), 0 TSRMLS_CC,
106- " JS exception thrown during __isset of \" %*s\" " ,
107- Z_STRLEN_P (member), Z_STRVAL_P (member));
108- return ;
109- }
113+ THROW_IF_EXCEPTION (" JS exception thrown during __isset of \" %*s\" " ,
114+ Z_STRLEN_P (member), Z_STRVAL_P (member));
110115 RETURN_BOOL (msg.retval_ .AsBool ());
111116}
112117
@@ -165,29 +170,88 @@ class JsReadPropertyMsg : public MessageToJs {
165170
166171PHP_METHOD (JsObject, __get) {
167172 zval *member;
168- if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, " z/" , &member) == FAILURE) {
169- zend_throw_exception (zend_exception_get_default (TSRMLS_C), " bad property name" , 0 TSRMLS_CC);
170- return ;
171- }
173+ PARSE_PARAMS (__get, " z/" , &member);
172174 convert_to_string (member);
173- node_php_jsobject *obj = (node_php_jsobject *)
174- zend_object_store_get_object (this_ptr TSRMLS_CC);
175175 JsReadPropertyMsg msg (obj->channel , obj->id , member, 0 );
176176 obj->channel ->Send (&msg);
177177 msg.WaitForResponse ();
178- // ok, result is in msg.retval_ or msg.exception_
179- if (msg.HasException ()) {
180- zend_throw_exception_ex (
181- zend_exception_get_default (TSRMLS_C), 0 TSRMLS_CC,
182- " JS exception thrown during __get of \" %*s\" " ,
183- Z_STRLEN_P (member), Z_STRVAL_P (member));
184- return ;
178+ THROW_IF_EXCEPTION (" JS exception thrown during __get of \" %*s\" " ,
179+ Z_STRLEN_P (member), Z_STRVAL_P (member));
180+ msg.retval_ .ToPhp (obj->channel , return_value, return_value_ptr TSRMLS_CC);
181+ }
182+
183+ class JsWritePropertyMsg : public MessageToJs {
184+ Value object_;
185+ Value member_;
186+ Value value_;
187+ public:
188+ JsWritePropertyMsg (ObjectMapper* m, objid_t objId, zval *member, zval *value)
189+ : MessageToJs(m), object_(), member_(m, member), value_(m, value) {
190+ object_.SetJsObject (objId);
191+ }
192+ protected:
193+ virtual void InJs (ObjectMapper *m) {
194+ v8::Local<v8::Object> jsObj = Nan::To<v8::Object>(object_.ToJs (m))
195+ .ToLocalChecked ();
196+ v8::Local<v8::String> jsKey = Nan::To<v8::String>(member_.ToJs (m))
197+ .ToLocalChecked ();
198+ v8::Local<v8::Value> jsVal = value_.ToJs (m);
199+
200+ if (Nan::Set (jsObj, jsKey, jsVal).FromMaybe (false )) {
201+ retval_.SetBool (true );
202+ }
203+ }
204+ };
205+
206+ PHP_METHOD (JsObject, __set) {
207+ zval *member; zval *value;
208+ PARSE_PARAMS (__set, " z/z" , &member, &value);
209+ convert_to_string (member);
210+ JsWritePropertyMsg msg (obj->channel , obj->id , member, value);
211+ obj->channel ->Send (&msg);
212+ msg.WaitForResponse ();
213+ THROW_IF_EXCEPTION (" JS exception thrown during __set of \" %*s\" " ,
214+ Z_STRLEN_P (member), Z_STRVAL_P (member));
215+ msg.retval_ .ToPhp (obj->channel , return_value, return_value_ptr TSRMLS_CC);
216+ }
217+
218+ class JsDeletePropertyMsg : public MessageToJs {
219+ Value object_;
220+ Value member_;
221+ public:
222+ JsDeletePropertyMsg (ObjectMapper* m, objid_t objId, zval *member)
223+ : MessageToJs(m), object_(), member_(m, member) {
224+ object_.SetJsObject (objId);
225+ }
226+ protected:
227+ virtual void InJs (ObjectMapper *m) {
228+ v8::Local<v8::Object> jsObj = Nan::To<v8::Object>(object_.ToJs (m))
229+ .ToLocalChecked ();
230+ v8::Local<v8::String> jsKey = Nan::To<v8::String>(member_.ToJs (m))
231+ .ToLocalChecked ();
232+
233+ if (Nan::Delete (jsObj, jsKey).FromMaybe (false )) {
234+ retval_.SetBool (true );
235+ }
185236 }
237+ };
238+
239+ PHP_METHOD (JsObject, __unset) {
240+ zval *member;
241+ PARSE_PARAMS (__unset, " z/" , &member);
242+ convert_to_string (member);
243+ JsDeletePropertyMsg msg (obj->channel , obj->id , member);
244+ obj->channel ->Send (&msg);
245+ msg.WaitForResponse ();
246+ THROW_IF_EXCEPTION (" JS exception thrown during __unset of \" %*s\" " ,
247+ Z_STRLEN_P (member), Z_STRVAL_P (member));
186248 msg.retval_ .ToPhp (obj->channel , return_value, return_value_ptr TSRMLS_CC);
187249}
188250
251+
189252/* Use (slightly thunked) versions of the has/read/write property handlers
190253 * for dimensions as well, so that $obj['foo'] acts like $obj->foo. */
254+
191255static int node_php_jsobject_has_dimension (zval *obj, zval *idx, int chk_type TSRMLS_DC) {
192256 // thunk!
193257 if (chk_type == 0 ) { chk_type = 2 ; }
@@ -285,10 +349,19 @@ STUB_METHOD(__construct)
285349STUB_METHOD(__sleep)
286350STUB_METHOD(__wakeup)
287351
288- ZEND_BEGIN_ARG_INFO_EX(node_php_jsobject_one_arg, 0 , 0 , 1 )
352+ #if USE_MAGIC_ISSET
353+ ZEND_BEGIN_ARG_INFO_EX (node_php_jsobject_isset_args, 0 , 0 , 1 )
354+ ZEND_ARG_INFO(0 , member)
355+ ZEND_END_ARG_INFO()
356+ #endif
357+ ZEND_BEGIN_ARG_INFO_EX (node_php_jsobject_get_args, 0 , 1 /* return by ref*/ , 1 )
358+ ZEND_ARG_INFO(0 , member)
359+ ZEND_END_ARG_INFO()
360+ ZEND_BEGIN_ARG_INFO_EX(node_php_jsobject_set_args, 0 , 0 , 2 )
289361 ZEND_ARG_INFO(0 , member)
362+ ZEND_ARG_INFO(0 , value)
290363ZEND_END_ARG_INFO()
291- ZEND_BEGIN_ARG_INFO_EX(node_php_jsobject_one_arg_retref , 0 , 1 , 1 )
364+ ZEND_BEGIN_ARG_INFO_EX(node_php_jsobject_unset_args , 0 , 0 , 1 )
292365 ZEND_ARG_INFO(0 , member)
293366ZEND_END_ARG_INFO()
294367
@@ -297,9 +370,11 @@ static const zend_function_entry node_php_jsobject_methods[] = {
297370 PHP_ME (JsObject, __sleep, NULL , ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
298371 PHP_ME (JsObject, __wakeup, NULL , ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
299372#if USE_MAGIC_ISSET
300- PHP_ME (JsObject, __isset, node_php_jsobject_one_arg , ZEND_ACC_PUBLIC)
373+ PHP_ME (JsObject, __isset, node_php_jsobject_isset_args , ZEND_ACC_PUBLIC)
301374#endif
302- PHP_ME (JsObject, __get, node_php_jsobject_one_arg_retref, ZEND_ACC_PUBLIC)
375+ PHP_ME (JsObject, __get, node_php_jsobject_get_args, ZEND_ACC_PUBLIC)
376+ PHP_ME (JsObject, __set, node_php_jsobject_set_args, ZEND_ACC_PUBLIC)
377+ PHP_ME (JsObject, __unset, node_php_jsobject_unset_args, ZEND_ACC_PUBLIC)
303378 ZEND_FE_END
304379};
305380
0 commit comments