📄 overload.c
字号:
int got_prop = 0; TSRMLS_FETCH(); INIT_PZVAL(result_ptr); for (element=property_reference->elements_list->head; element; element=element->next) { overloaded_property = (zend_overloaded_element *) element->data; ZVAL_NULL(result_ptr); if (Z_TYPE_P(overloaded_property) == OE_IS_OBJECT) { /* Trying to access a property on a non-object. */ if (Z_TYPE(object) != IS_OBJECT) { CLEANUP_OO_CHAIN(); if (got_prop) zval_dtor(&object); return result; } if (zend_hash_find(Z_OBJPROP(object), Z_STRVAL(overloaded_property->element), Z_STRLEN(overloaded_property->element)+1, (void **)&real_prop) == SUCCESS) { result = **real_prop; /* printf("is_ref: %d, refcount: %d\n", (*real_prop)->is_ref, (*real_prop)->refcount); */ /* REPLACE_ZVAL_VALUE(&result_ptr, *real_prop, 1); */ } else if (Z_OBJCE(object)->handle_property_get == overload_get_property && call_get_handler(&object, &overloaded_property->element, &result_ptr TSRMLS_CC)) { got_prop = 1; } else { php_error(E_NOTICE, "Undefined property: %s", Z_STRVAL(overloaded_property->element)); CLEANUP_OO_CHAIN(); if (got_prop) zval_dtor(&object); return result; } } else if (Z_TYPE_P(overloaded_property) == OE_IS_ARRAY) { /* Trying to access index on a non-array. */ if (Z_TYPE(object) != IS_ARRAY) { CLEANUP_OO_CHAIN(); if (got_prop) zval_dtor(&object); return result; } if (Z_TYPE(overloaded_property->element) == IS_STRING) { if (zend_hash_find(Z_ARRVAL(object), Z_STRVAL(overloaded_property->element), Z_STRLEN(overloaded_property->element)+1, (void **)&real_prop) == FAILURE) { CLEANUP_OO_CHAIN(); if (got_prop) zval_dtor(&object); return result; } } else if (Z_TYPE(overloaded_property->element) == IS_LONG) { if (zend_hash_index_find(Z_ARRVAL(object), Z_LVAL(overloaded_property->element), (void **)&real_prop) == FAILURE) { CLEANUP_OO_CHAIN(); if (got_prop) zval_dtor(&object); return result; } } result = **real_prop; } zval_dtor(&overloaded_property->element); /* printf("got_prop: %d\n", got_prop); */ if (element != property_reference->elements_list->head && got_prop) { zval_dtor(&object); got_prop = 0; } object = result; } if (!got_prop) zval_copy_ctor(&result); return result;}/* }}} *//* {{{ int overload_set_property() */static int overload_set_property(zend_property_reference *property_reference, zval *value){ zval result; zval *result_ptr = &result; zend_overloaded_element *overloaded_property; zend_llist_element *element; zval **object = &property_reference->object; TSRMLS_FETCH(); for (element=property_reference->elements_list->head; element; element=element->next) { overloaded_property = (zend_overloaded_element *) element->data; ZVAL_NULL(result_ptr); if (Z_TYPE_P(overloaded_property) == OE_IS_OBJECT) { /* Trying to access a property on a non-object. */ if (Z_TYPE_PP(object) != IS_OBJECT) { CLEANUP_OO_CHAIN(); return FAILURE; } if (zend_hash_find(Z_OBJPROP_PP(object), Z_STRVAL(overloaded_property->element), Z_STRLEN(overloaded_property->element)+1, (void **)&object) == FAILURE) { if (element == property_reference->elements_list->tail) { if (Z_OBJCE_PP(object)->handle_property_set == overload_set_property && call_set_handler(*object, &overloaded_property->element, value TSRMLS_CC)) { CLEANUP_OO_CHAIN(); return SUCCESS; } else { php_error(E_WARNING, "Unable to set property: %s", Z_STRVAL(overloaded_property->element)); CLEANUP_OO_CHAIN(); return FAILURE; } } if (Z_OBJCE_PP(object)->handle_property_get == overload_get_property && call_get_handler(*object, &overloaded_property->element, &result_ptr TSRMLS_CC)) { object = &result_ptr; } else { php_error(E_NOTICE, "Undefined property: %s", Z_STRVAL(overloaded_property->element)); CLEANUP_OO_CHAIN(); return FAILURE; } } } else if (Z_TYPE_P(overloaded_property) == OE_IS_ARRAY) { } zval_dtor(&overloaded_property->element); } /* printf("value is_ref: %d, refcount: %d\n", value->is_ref, value->refcount); */ REPLACE_ZVAL_VALUE(object, value, 1); /* printf("object is_ref: %d, refcount: %d\n", (*object)->is_ref, (*object)->refcount); */ return SUCCESS;}/* }}} *//* {{{ void overload_call_method() */static void overload_call_method(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference){ zval ***args; zval *retval = NULL; int call_result; zend_bool use_call_handler = 1; zval *object = property_reference->object; zval call_handler, method_name, *method_name_ptr = &method_name; zend_overloaded_element *method = (zend_overloaded_element *)property_reference->elements_list->tail->data; /* * We don't use the call handler if the invoked method exists in object's * method table. */ if (zend_hash_exists(&Z_OBJCE_P(object)->function_table, Z_STRVAL(method->element), Z_STRLEN(method->element) + 1)) { use_call_handler = 0; } args = (zval ***)emalloc(ZEND_NUM_ARGS() * sizeof(zval **)); if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { efree(args); php_error(E_WARNING, "unable to obtain arguments"); return; } if (use_call_handler) { zval **handler_args[3]; zval *arg_array; zval result, *result_ptr = &result; zend_class_entry temp_ce, *orig_ce; int i; temp_ce = *Z_OBJCE_P(object); DISABLE_HANDLERS(temp_ce); orig_ce = Z_OBJCE_P(object); Z_OBJ_P(object)->ce = &temp_ce; ZVAL_STRINGL(&call_handler, CALL_HANDLER, sizeof(CALL_HANDLER)-1, 0); ZVAL_STRINGL(&method_name, Z_STRVAL(method->element), Z_STRLEN(method->element), 0); INIT_PZVAL(&call_handler); INIT_PZVAL(method_name_ptr); MAKE_STD_ZVAL(arg_array); array_init(arg_array); for (i = 0; i < ZEND_NUM_ARGS(); i++) { zval_add_ref(args[i]); add_next_index_zval(arg_array, *args[i]); } result_ptr->is_ref = 1; result_ptr->refcount = 1; ZVAL_NULL(result_ptr); handler_args[0] = &method_name_ptr; handler_args[1] = &arg_array; handler_args[2] = &result_ptr; call_result = call_user_function_ex(NULL, &object, &call_handler, &retval, 3, handler_args, 0, NULL TSRMLS_CC); Z_OBJ_P(object)->ce = orig_ce; zval_ptr_dtor(&arg_array); if (call_result == FAILURE || !retval) { efree(args); zval_dtor(result_ptr); php_error(E_WARNING, "unable to call %s::" CALL_HANDLER "() handler", Z_OBJCE_P(object)->name); return; } if (zval_is_true(retval)) { REPLACE_ZVAL_VALUE(&return_value, result_ptr, 1); } else { zval_dtor(result_ptr); php_error(E_WARNING, "Call to undefined method %s::%s()", Z_OBJCE_P(object)->name, Z_STRVAL(method_name)); } zval_ptr_dtor(&retval); } else { call_result = call_user_function_ex(NULL, &object, &method->element, &retval, ZEND_NUM_ARGS(), args, 0, NULL TSRMLS_CC); if (call_result == FAILURE || !retval) { efree(args); php_error(E_WARNING, "unable to call %s::%s() method", Z_OBJCE_P(object)->name, Z_STRVAL(method->element)); return; } REPLACE_ZVAL_VALUE(&return_value, retval, 1); zval_ptr_dtor(&retval); } efree(args); zval_dtor(&method->element);}/* }}} *//* {{{ static int locate_accessors() */static int locate_accessors(zend_function *method, oo_class_data *oo_data TSRMLS_DC){ zval *accessor_name; char *function_name = method->common.function_name; int function_name_len = strlen(method->common.function_name); if (!strncmp(function_name, GET_HANDLER "_", sizeof(GET_HANDLER "_")-1)) { MAKE_STD_ZVAL(accessor_name); ZVAL_STRINGL(accessor_name, function_name, function_name_len, 1); zend_hash_update(&oo_data->getters, function_name + sizeof(GET_HANDLER "_") - 1, function_name_len - sizeof(GET_HANDLER "_") + 2, (void *)&accessor_name, sizeof(zval *), NULL); } else if (!strncmp(function_name, SET_HANDLER "_", sizeof(SET_HANDLER "_")-1)) { MAKE_STD_ZVAL(accessor_name); ZVAL_STRINGL(accessor_name, function_name, function_name_len, 1); zend_hash_update(&oo_data->setters, function_name + sizeof(SET_HANDLER "_") - 1, function_name_len - sizeof(SET_HANDLER "_") + 2, (void *)&accessor_name, sizeof(zval *), NULL); } return 0;}/* }}} *//* {{{ proto void overload(string class_entry) Enables property and method call overloading for a class. */PHP_FUNCTION(overload){ char *class_entry = NULL; int argc = ZEND_NUM_ARGS(); int class_entry_len; zend_class_entry *ce = NULL; oo_class_data oo_data; if (zend_parse_parameters(argc TSRMLS_CC, "s/", &class_entry, &class_entry_len) == FAILURE) return; zend_str_tolower(class_entry, class_entry_len); if (zend_hash_find(EG(class_table), class_entry, class_entry_len+1, (void**)&ce) == FAILURE) { php_error(E_WARNING, "%s() was unable to locate class '%s'", get_active_function_name(TSRMLS_C), class_entry); RETURN_FALSE; } /* Check if the handlers have already been installed for this class. */ if (zend_hash_index_exists(&OOG(overloaded_classes), (long)ce)) { RETURN_TRUE; } zend_hash_init(&oo_data.getters, 10, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&oo_data.setters, 10, NULL, ZVAL_PTR_DTOR, 0); zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)locate_accessors, (void *)&oo_data TSRMLS_CC); if (zend_hash_exists(&ce->function_table, GET_HANDLER, sizeof(GET_HANDLER)) || zend_hash_num_elements(&oo_data.getters)) { oo_data.handle_property_get = ce->handle_property_get; ce->handle_property_get = overload_get_property; } else oo_data.handle_property_get = NULL; if (zend_hash_exists(&ce->function_table, SET_HANDLER, sizeof(SET_HANDLER)) || zend_hash_num_elements(&oo_data.setters)) { oo_data.handle_property_set = ce->handle_property_set; ce->handle_property_set = overload_set_property; } else oo_data.handle_property_set = NULL; if (zend_hash_exists(&ce->function_table, CALL_HANDLER, sizeof(CALL_HANDLER))) { oo_data.handle_function_call = ce->handle_function_call; ce->handle_function_call = overload_call_method; } else oo_data.handle_function_call = NULL; zend_hash_index_update(&OOG(overloaded_classes), (long)ce, &oo_data, sizeof(oo_data), NULL); RETURN_TRUE;}/* }}} */#endif /* HAVE_OVERLOAD */#endif /* ZEND_ENGINE_2 *//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -