static PHP_METHOD(Hello, addProperties) { zval *obj; obj = getThis(); /*add zval property*/ zval *arr; MAKE_STD_ZVAL(arr); array_init(arr); add_assoc_string(arr, "e", "hello", 1); add_index_string(arr, 1, "hello1111", 1); add_property_zval_ex(obj, "persons", strlen("persons")+1, arr TSRMLS_CC); Z_DELREF_P(arr); /*add double property*/ add_property_double(obj, "d", 10.5); /*add bool property*/ add_property_bool(obj, "b", 1); /*add string property*/ char *str = "hello str"; add_property_string(obj, "str", str, 1); /*add long property*/ add_property_long(obj, "l", 12); }
/** * Start a batch of RPC actions. * @param array batch Array of actions to take * @return object Object with results of all actions */ PHP_METHOD(Call, startBatch) { wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis()); grpc_op ops[8]; size_t op_num = 0; zval *array; zval *value; zval *inner_value; HashTable *array_hash; HashPosition array_pointer; HashTable *status_hash; HashTable *message_hash; zval *message_value; zval *message_flags; zend_string *key; zend_ulong index; grpc_metadata_array metadata; grpc_metadata_array trailing_metadata; grpc_metadata_array recv_metadata; grpc_metadata_array recv_trailing_metadata; grpc_status_code status; char *status_details = NULL; size_t status_details_capacity = 0; grpc_byte_buffer *message; int cancelled; grpc_call_error error; char *message_str; size_t message_len; zval recv_status; grpc_metadata_array_init(&metadata); grpc_metadata_array_init(&trailing_metadata); grpc_metadata_array_init(&recv_metadata); grpc_metadata_array_init(&recv_trailing_metadata); object_init(return_value); /* "a" == 1 array */ #ifndef FAST_ZPP if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &array) == FAILURE) { zend_throw_exception(spl_ce_InvalidArgumentException, "start_batch expects an array", 1); goto cleanup; } #else ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ARRAY(array) ZEND_PARSE_PARAMETERS_END(); #endif array_hash = HASH_OF(array); //TODO(thinkerou): why phpunit wrong when use ZEND_HASH_FOREACH_VAL marco? //ZEND_HASH_FOREACH_VAL(array_hash, value) { for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer); (value = zend_hash_get_current_data_ex(array_hash, &array_pointer)) != NULL; zend_hash_move_forward_ex(array_hash, &array_pointer)) { if (zend_hash_get_current_key_ex(array_hash, &key, &index, &array_pointer) != HASH_KEY_IS_LONG) { zend_throw_exception(spl_ce_InvalidArgumentException, "batch keys must be integers", 1); goto cleanup; } switch(index) { case GRPC_OP_SEND_INITIAL_METADATA: if (!create_metadata_array(value, &metadata)) { zend_throw_exception(spl_ce_InvalidArgumentException, "Bad metadata value given", 1); goto cleanup; } ops[op_num].data.send_initial_metadata.count = metadata.count; ops[op_num].data.send_initial_metadata.metadata = metadata.metadata; break; case GRPC_OP_SEND_MESSAGE: if (Z_TYPE_P(value) != IS_ARRAY) { zend_throw_exception(spl_ce_InvalidArgumentException, "Expected an array for send message", 1); goto cleanup; } message_hash = HASH_OF(value); if ((message_flags = zend_hash_str_find(message_hash, "flags", sizeof("flags") - 1)) != NULL) { if (Z_TYPE_P(message_flags) != IS_LONG) { zend_throw_exception(spl_ce_InvalidArgumentException, "Expected an int for message flags", 1); } ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK; } if ((message_value = zend_hash_str_find( message_hash, "message", sizeof("message") - 1)) == NULL || Z_TYPE_P(message_value) != IS_STRING) { zend_throw_exception(spl_ce_InvalidArgumentException, "Expected a string for send message", 1); goto cleanup; } ops[op_num].data.send_message = string_to_byte_buffer(Z_STRVAL_P(message_value), Z_STRLEN_P(message_value)); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: break; case GRPC_OP_SEND_STATUS_FROM_SERVER: status_hash = HASH_OF(value); if ((inner_value = zend_hash_str_find( status_hash, "metadata", sizeof("metadata") - 1)) != NULL) { if (!create_metadata_array(inner_value, &trailing_metadata)) { zend_throw_exception(spl_ce_InvalidArgumentException, "Bad trailing metadata value given", 1); goto cleanup; } ops[op_num].data.send_status_from_server.trailing_metadata = trailing_metadata.metadata; ops[op_num].data.send_status_from_server.trailing_metadata_count = trailing_metadata.count; } if ((inner_value = zend_hash_str_find( status_hash, "code", sizeof("code") - 1)) != NULL) { if (Z_TYPE_P(inner_value) != IS_LONG) { zend_throw_exception(spl_ce_InvalidArgumentException, "Status code must be an integer", 1); goto cleanup; } ops[op_num].data.send_status_from_server.status = Z_LVAL_P(inner_value); } else { zend_throw_exception(spl_ce_InvalidArgumentException, "Integer status code is required", 1); goto cleanup; } if ((inner_value = zend_hash_str_find( status_hash, "details", sizeof("details") - 1)) != NULL) { if (Z_TYPE_P(inner_value) != IS_STRING) { zend_throw_exception(spl_ce_InvalidArgumentException, "Status details must be a string", 1); goto cleanup; } ops[op_num].data.send_status_from_server.status_details = Z_STRVAL_P(inner_value); } else { zend_throw_exception(spl_ce_InvalidArgumentException, "String status details is required", 1); goto cleanup; } break; case GRPC_OP_RECV_INITIAL_METADATA: ops[op_num].data.recv_initial_metadata = &recv_metadata; break; case GRPC_OP_RECV_MESSAGE: ops[op_num].data.recv_message = &message; break; case GRPC_OP_RECV_STATUS_ON_CLIENT: ops[op_num].data.recv_status_on_client.trailing_metadata = &recv_trailing_metadata; ops[op_num].data.recv_status_on_client.status = &status; ops[op_num].data.recv_status_on_client.status_details = &status_details; ops[op_num].data.recv_status_on_client.status_details_capacity = &status_details_capacity; break; case GRPC_OP_RECV_CLOSE_ON_SERVER: ops[op_num].data.recv_close_on_server.cancelled = &cancelled; break; default: zend_throw_exception(spl_ce_InvalidArgumentException, "Unrecognized key in batch", 1); goto cleanup; } ops[op_num].op = (grpc_op_type)index; ops[op_num].flags = 0; ops[op_num].reserved = NULL; op_num++; } //ZEND_HASH_FOREACH_END(); error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped, NULL); if (error != GRPC_CALL_OK) { zend_throw_exception(spl_ce_LogicException, "start_batch was called incorrectly", (long)error); goto cleanup; } grpc_completion_queue_pluck(completion_queue, call->wrapped, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); for (int i = 0; i < op_num; i++) { switch(ops[i].op) { case GRPC_OP_SEND_INITIAL_METADATA: add_property_bool(return_value, "send_metadata", true); break; case GRPC_OP_SEND_MESSAGE: add_property_bool(return_value, "send_message", true); break; case GRPC_OP_SEND_CLOSE_FROM_CLIENT: add_property_bool(return_value, "send_close", true); break; case GRPC_OP_SEND_STATUS_FROM_SERVER: add_property_bool(return_value, "send_status", true); break; case GRPC_OP_RECV_INITIAL_METADATA: grpc_parse_metadata_array(&recv_metadata, array); add_property_zval(return_value, "metadata", array); //Z_DELREF_P(array); break; case GRPC_OP_RECV_MESSAGE: byte_buffer_to_string(message, &message_str, &message_len); if (message_str == NULL) { add_property_null(return_value, "message"); } else { add_property_stringl(return_value, "message", message_str, message_len); } break; case GRPC_OP_RECV_STATUS_ON_CLIENT: object_init(&recv_status); grpc_parse_metadata_array(&recv_trailing_metadata, array); add_property_zval(&recv_status, "metadata", array); //Z_DELREF_P(array); add_property_long(&recv_status, "code", status); add_property_string(&recv_status, "details", status_details); add_property_zval(return_value, "status", &recv_status); //Z_DELREF_P(&recv_status); break; case GRPC_OP_RECV_CLOSE_ON_SERVER: add_property_bool(return_value, "cancelled", cancelled); break; default: break; } } cleanup: grpc_metadata_array_destroy(&metadata); grpc_metadata_array_destroy(&trailing_metadata); grpc_metadata_array_destroy(&recv_metadata); grpc_metadata_array_destroy(&recv_trailing_metadata); if (status_details != NULL) { gpr_free(status_details); } for (int i = 0; i < op_num; i++) { if (ops[i].op == GRPC_OP_SEND_MESSAGE) { grpc_byte_buffer_destroy(ops[i].data.send_message); } if (ops[i].op == GRPC_OP_RECV_MESSAGE) { grpc_byte_buffer_destroy(message); } } RETURN_DESTROY_ZVAL(return_value); }