add some macro to reduce duplicate code
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 706c7d8..46591d8 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -73,15 +73,7 @@
  * of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_call(zend_class_entry *class_type
                                               TSRMLS_DC) {
-  wrapped_grpc_call *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_call *)emalloc(sizeof(wrapped_grpc_call));
-  memset(intern, 0, sizeof(wrapped_grpc_call));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_call) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7
@@ -111,11 +103,7 @@
   char *str_key;
   char *str_val;
   size_t key_len;
-#if PHP_MAJOR_VERSION < 7
-  zval **data = NULL;
-#else
- zval *data;
-#endif
+  zval *data = NULL;
 
   array_hash = Z_ARRVAL_P(array);
   grpc_metadata *elem;
@@ -126,14 +114,9 @@
     memcpy(str_key, elem->key, key_len);
     str_val = ecalloc(elem->value_length + 1, sizeof(char));
     memcpy(str_val, elem->value, elem->value_length);
-#if PHP_MAJOR_VERSION < 7
-    if (zend_hash_find(array_hash, str_key, key_len, (void **)data) ==
+    if (php_grpc_zend_hash_find(array_hash, str_key, key_len, (void **)&data) ==
         SUCCESS) {
-      if (Z_TYPE_P(*data) != IS_ARRAY) {
-#else
-    if ((data = zend_hash_str_find(array_hash, str_key, key_len)) != NULL) {
       if (Z_TYPE_P(data) != IS_ARRAY) {
-#endif
         zend_throw_exception(zend_exception_get_default(TSRMLS_C),
                              "Metadata hash somehow contains wrong types.",
                              1 TSRMLS_CC);
@@ -141,13 +124,8 @@
         efree(str_val);
         return NULL;
       }
-#if PHP_MAJOR_VERSION < 7
-      php_grpc_add_next_index_stringl(*data, str_val, elem->value_length,
-                                      false);
-#else
       php_grpc_add_next_index_stringl(data, str_val, elem->value_length,
                                       false);
-#endif
     } else {
       PHP_GRPC_MAKE_STD_ZVAL(inner_array);
       array_init(inner_array);
@@ -164,96 +142,48 @@
 bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
   HashTable *array_hash;
   HashTable *inner_array_hash;
-#if PHP_MAJOR_VERSION < 7
-  zval **inner_array;
-  zval **value;
-  HashPosition array_pointer;
-  HashPosition inner_array_pointer;
-  char *key;
-  uint key_len;
-  ulong index;
-#else
-  zval *inner_array;
   zval *value;
-  zend_string *key;
-#endif
+  zval *inner_array;
   if (Z_TYPE_P(array) != IS_ARRAY) {
     return false;
   }
   grpc_metadata_array_init(metadata);
   array_hash = Z_ARRVAL_P(array);
-#if PHP_MAJOR_VERSION < 7
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
-      return false;
-    }
-    if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
-      return false;
-    }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    metadata->capacity += zend_hash_num_elements(inner_array_hash);
-  }
-#else
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
-    if (key == NULL) {
+
+  char *key = NULL;
+  int key_type;
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type,
+                                          inner_array)
+    if (key_type != HASH_KEY_IS_STRING) {
       return false;
     }
     if (Z_TYPE_P(inner_array) != IS_ARRAY) {
       return false;
     }
-    inner_array_hash = HASH_OF(inner_array);
+    inner_array_hash = Z_ARRVAL_P(inner_array);
     metadata->capacity += zend_hash_num_elements(inner_array_hash);
-  } ZEND_HASH_FOREACH_END();
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 
   metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
 
-#if PHP_MAJOR_VERSION < 7
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
+  char *key1 = NULL;
+  int key_type1;
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key1, key_type1,
+                                          inner_array)
+    if (key_type1 != HASH_KEY_IS_STRING) {
       return false;
     }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
-                                             &inner_array_pointer);
-         zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
-                                       &inner_array_pointer) == SUCCESS;
-         zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
-      if (Z_TYPE_P(*value) != IS_STRING) {
-        return false;
-      }
-      metadata->metadata[metadata->count].key = key;
-      metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
-      metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
-      metadata->count += 1;
-    }
-  }
-#else
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
-    if (key == NULL) {
-      return false;
-    }
-    inner_array_hash = HASH_OF(inner_array);
-
-    ZEND_HASH_FOREACH_VAL(inner_array_hash, value) {
+    inner_array_hash = Z_ARRVAL_P(inner_array);
+    PHP_GRPC_HASH_FOREACH_VAL_START(inner_array_hash, value)
       if (Z_TYPE_P(value) != IS_STRING) {
         return false;
       }
-      metadata->metadata[metadata->count].key = ZSTR_VAL(key);
+      metadata->metadata[metadata->count].key = key1;
       metadata->metadata[metadata->count].value = Z_STRVAL_P(value);
       metadata->metadata[metadata->count].value_length = Z_STRLEN_P(value);
       metadata->count += 1;
-    } ZEND_HASH_FOREACH_END();
-  } ZEND_HASH_FOREACH_END();
-#endif
+    PHP_GRPC_HASH_FOREACH_END()
+  PHP_GRPC_HASH_FOREACH_END()
   return true;
 }
 
@@ -321,23 +251,13 @@
   PHP_GRPC_MAKE_STD_ZVAL(result);
   object_init(result);
   php_grpc_ulong index;
-#if PHP_MAJOR_VERSION < 7
-  zval **value;
-  zval **inner_value;
-  HashPosition array_pointer;
-  zval **message_value;
-  zval **message_flags;
-  char *key;
-  uint key_len;
   zval *recv_status;
-#else
+  PHP_GRPC_MAKE_STD_ZVAL(recv_status);
+  object_init(recv_status);
   zval *value;
   zval *inner_value;
   zval *message_value;
   zval *message_flags;
-  zend_string *key;
-  zval recv_status;
-#endif
   wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
   
   grpc_op ops[8];
@@ -371,26 +291,23 @@
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
       FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "start_batch expects an array", 1 TSRMLS_CC);
-    goto cleanup;
+                         "start_batch expects an array", 1 TSRMLS_CC); goto cleanup;
   }
 
-#if PHP_MAJOR_VERSION < 7
-
   array_hash = Z_ARRVAL_P(array);
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&value,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_LONG) {
+
+  char *key = NULL;
+  int key_type;
+  PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(array_hash, key, key_type, index,
+                                          value)
+    if (key_type != HASH_KEY_IS_LONG) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "batch keys must be integers", 1 TSRMLS_CC);
       goto cleanup;
     }
     switch(index) {
     case GRPC_OP_SEND_INITIAL_METADATA:
-      if (!create_metadata_array(*value, &metadata)) {
+      if (!create_metadata_array(value, &metadata)) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Bad metadata value given", 1 TSRMLS_CC);
         goto cleanup;
@@ -401,41 +318,41 @@
           metadata.metadata;
       break;
     case GRPC_OP_SEND_MESSAGE:
-      if (Z_TYPE_PP(value) != IS_ARRAY) {
+      if (Z_TYPE_P(value) != IS_ARRAY) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Expected an array for send message",
                              1 TSRMLS_CC);
         goto cleanup;
       }
-      message_hash = Z_ARRVAL_PP(value);
-      if (zend_hash_find(message_hash, "flags", sizeof("flags"),
+      message_hash = Z_ARRVAL_P(value);
+      if (php_grpc_zend_hash_find(message_hash, "flags", sizeof("flags"),
                          (void **)&message_flags) == SUCCESS) {
-        if (Z_TYPE_PP(message_flags) != IS_LONG) {
+        if (Z_TYPE_P(message_flags) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Expected an int for message flags",
                                1 TSRMLS_CC);
         }
-        ops[op_num].flags = Z_LVAL_PP(message_flags) & GRPC_WRITE_USED_MASK;
+        ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
       }
-      if (zend_hash_find(message_hash, "message", sizeof("message"),
+      if (php_grpc_zend_hash_find(message_hash, "message", sizeof("message"),
                          (void **)&message_value) != SUCCESS ||
-          Z_TYPE_PP(message_value) != IS_STRING) {
+          Z_TYPE_P(message_value) != IS_STRING) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Expected a string for send message",
                              1 TSRMLS_CC);
         goto cleanup;
       }
       ops[op_num].data.send_message =
-          string_to_byte_buffer(Z_STRVAL_PP(message_value),
-                                Z_STRLEN_PP(message_value));
+          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 = Z_ARRVAL_PP(value);
-      if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
+      status_hash = Z_ARRVAL_P(value);
+      if (php_grpc_zend_hash_find(status_hash, "metadata", sizeof("metadata"),
                          (void **)&inner_value) == SUCCESS) {
-        if (!create_metadata_array(*inner_value, &trailing_metadata)) {
+        if (!create_metadata_array(inner_value, &trailing_metadata)) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Bad trailing metadata value given",
                                1 TSRMLS_CC);
@@ -446,32 +363,32 @@
         ops[op_num].data.send_status_from_server.trailing_metadata_count =
             trailing_metadata.count;
       }
-      if (zend_hash_find(status_hash, "code", sizeof("code"),
+      if (php_grpc_zend_hash_find(status_hash, "code", sizeof("code"),
                          (void**)&inner_value) == SUCCESS) {
-        if (Z_TYPE_PP(inner_value) != IS_LONG) {
+        if (Z_TYPE_P(inner_value) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Status code must be an integer",
                                1 TSRMLS_CC);
           goto cleanup;
         }
         ops[op_num].data.send_status_from_server.status =
-            Z_LVAL_PP(inner_value);
+            Z_LVAL_P(inner_value);
       } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Integer status code is required",
                              1 TSRMLS_CC);
         goto cleanup;
       }
-      if (zend_hash_find(status_hash, "details", sizeof("details"),
+      if (php_grpc_zend_hash_find(status_hash, "details", sizeof("details"),
                          (void**)&inner_value) == SUCCESS) {
-        if (Z_TYPE_PP(inner_value) != IS_STRING) {
+        if (Z_TYPE_P(inner_value) != IS_STRING) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Status details must be a string",
                                1 TSRMLS_CC);
           goto cleanup;
         }
         ops[op_num].data.send_status_from_server.status_details =
-            Z_STRVAL_PP(inner_value);
+            Z_STRVAL_P(inner_value);
       } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "String status details is required",
@@ -506,131 +423,7 @@
     ops[op_num].flags = 0;
     ops[op_num].reserved = NULL;
     op_num++;
-  }
-
-#else
-
-  array_hash = HASH_OF(array);
-  ZEND_HASH_FOREACH_KEY_VAL(array_hash, index, key, value) {
-    if (key) {
-      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();
-
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 
   error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
                                 NULL);
@@ -642,7 +435,9 @@
   }
   grpc_completion_queue_pluck(completion_queue, call->wrapped,
                               gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+  zval recv_md;
+#endif
   for (int i = 0; i < op_num; i++) {
     switch(ops[i].op) {
     case GRPC_OP_SEND_INITIAL_METADATA:
@@ -658,73 +453,37 @@
       add_property_bool(result, "send_status", true);
       break;
     case GRPC_OP_RECV_INITIAL_METADATA:
+#if PHP_MAJOR_VERSION < 7
       array = grpc_parse_metadata_array(&recv_metadata TSRMLS_CC);
       add_property_zval(result, "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(result, "message");
-      } else {
-        add_property_stringl(result, "message", message_str, message_len,
-                             false);
-      }
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      MAKE_STD_ZVAL(recv_status);
-      object_init(recv_status);
-      array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
-      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, true);
-      add_property_zval(result, "status", recv_status);
-      Z_DELREF_P(recv_status);
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      add_property_bool(result, "cancelled", cancelled);
-      break;
-    default:
-      break;
-    }
-  }
 #else
-  zval recv_md;
-  for (int i = 0; i < op_num; i++) {
-    switch(ops[i].op) {
-    case GRPC_OP_SEND_INITIAL_METADATA:
-      add_property_bool(result, "send_metadata", true);
-      break;
-    case GRPC_OP_SEND_MESSAGE:
-      add_property_bool(result, "send_message", true);
-      break;
-    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-      add_property_bool(result, "send_close", true);
-      break;
-    case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      add_property_bool(result, "send_status", true);
-      break;
-    case GRPC_OP_RECV_INITIAL_METADATA:
       recv_md = *grpc_parse_metadata_array(&recv_metadata);
       add_property_zval(result, "metadata", &recv_md);
+#endif
+      PHP_GRPC_DELREF(array);
       break;
     case GRPC_OP_RECV_MESSAGE:
       byte_buffer_to_string(message, &message_str, &message_len);
       if (message_str == NULL) {
         add_property_null(result, "message");
       } else {
-        add_property_stringl(result, "message", message_str,
-                             message_len);
+        php_grpc_add_property_stringl(result, "message", message_str,
+                                      message_len, false);
       }
       break;
     case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      object_init(&recv_status);
+#if PHP_MAJOR_VERSION < 7
+      array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
+      add_property_zval(recv_status, "metadata", array);
+#else
       recv_md = *grpc_parse_metadata_array(&recv_trailing_metadata);
-      add_property_zval(&recv_status, "metadata", &recv_md);
-      add_property_long(&recv_status, "code", status);
-      add_property_string(&recv_status, "details", status_details);
-      add_property_zval(result, "status", &recv_status);
+      add_property_zval(recv_status, "metadata", &recv_md);
+#endif
+      PHP_GRPC_DELREF(array);
+      add_property_long(recv_status, "code", status);
+      php_grpc_add_property_string(recv_status, "details", status_details, true);
+      add_property_zval(result, "status", recv_status);
+      PHP_GRPC_DELREF(recv_status);
       break;
     case GRPC_OP_RECV_CLOSE_ON_SERVER:
       add_property_bool(result, "cancelled", cancelled);
@@ -733,7 +492,6 @@
       break;
     }
   }
-#endif
 
 cleanup:
   grpc_metadata_array_destroy(&metadata);
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 0c55745..b7d33d7 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -67,16 +67,7 @@
  * associated with an object of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_call_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  wrapped_grpc_call_credentials *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_call_credentials *)emalloc(
-      sizeof(wrapped_grpc_call_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_call_credentials));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_call_credentials) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 6926484..325e8f4 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -71,15 +71,7 @@
  * object of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
                                                  TSRMLS_DC) {
-  wrapped_grpc_channel *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_channel *)emalloc(sizeof(wrapped_grpc_channel));
-  memset(intern, 0, sizeof(wrapped_grpc_channel));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_channel) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7
@@ -98,16 +90,6 @@
                               grpc_channel_args *args TSRMLS_DC) {
   HashTable *array_hash;
   int args_index;
-#if PHP_MAJOR_VERSION < 7
-  HashPosition array_pointer;
-  zval **data;
-  char *key;
-  uint key_len;
-  ulong index;
-#else
-  zval *data;
-  zend_string *key;
-#endif
   array_hash = Z_ARRVAL_P(args_array);
   if (!array_hash) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
@@ -118,41 +100,17 @@
   args->args = ecalloc(args->num_args, sizeof(grpc_arg));
   args_index = 0;
 
-#if PHP_MAJOR_VERSION < 7
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void **)&data,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
+  char *key = NULL;
+  zval *data;
+  int key_type;
+
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type, data)
+    if (key_type != HASH_KEY_IS_STRING) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "args keys must be strings", 1 TSRMLS_CC);
       return;
     }
     args->args[args_index].key = key;
-    switch (Z_TYPE_P(*data)) {
-    case IS_LONG:
-      args->args[args_index].value.integer = (int)Z_LVAL_P(*data);
-      args->args[args_index].type = GRPC_ARG_INTEGER;
-      break;
-    case IS_STRING:
-      args->args[args_index].value.string = Z_STRVAL_P(*data);
-      args->args[args_index].type = GRPC_ARG_STRING;
-      break;
-    default:
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args values must be int or string", 1 TSRMLS_CC);
-      return;
-    }
-    args_index++;
-  }
-#else
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, data) {
-    if (key == NULL) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args keys must be strings", 1);
-    }
-    args->args[args_index].key = ZSTR_VAL(key);
     switch (Z_TYPE_P(data)) {
     case IS_LONG:
       args->args[args_index].value.integer = (int)Z_LVAL_P(data);
@@ -164,12 +122,11 @@
       break;
     default:
       zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args values must be int or string", 1);
+                           "args values must be int or string", 1 TSRMLS_CC);
       return;
     }
     args_index++;
-  } ZEND_HASH_FOREACH_END();
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 }
 
 /**
@@ -181,11 +138,7 @@
  */
 PHP_METHOD(Channel, __construct) {
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
-#if PHP_MAJOR_VERSION < 7
-  zval **creds_obj = NULL;
-#else
   zval *creds_obj = NULL;
-#endif
   char *target;
   php_grpc_int target_length;
   zval *args_array = NULL;
@@ -200,43 +153,23 @@
                          "Channel expects a string and an array", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
   array_hash = Z_ARRVAL_P(args_array);
-  if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
+  if (php_grpc_zend_hash_find(array_hash, "credentials", sizeof("credentials"),
                      (void **)&creds_obj) == SUCCESS) {
-    if (Z_TYPE_P(*creds_obj) == IS_NULL) {
+    if (Z_TYPE_P(creds_obj) == IS_NULL) {
       creds = NULL;
-      zend_hash_del(array_hash, "credentials", 12);
-    } else if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
-        grpc_ce_channel_credentials) {
+      php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
+    } else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
+               grpc_ce_channel_credentials) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "credentials must be a ChannelCredentials object",
                            1 TSRMLS_CC);
       return;
     } else {
-      creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
-          *creds_obj TSRMLS_CC);
-      zend_hash_del(array_hash, "credentials", 12);
-    }
-  }
-#else
-  array_hash = HASH_OF(args_array);
-  if ((creds_obj = zend_hash_str_find(array_hash, "credentials",
-                                      sizeof("credentials") - 1)) != NULL) {
-    if (Z_TYPE_P(creds_obj) == IS_NULL) {
-      creds = NULL;
-      zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
-    } else if (Z_OBJ_P(creds_obj)->ce != grpc_ce_channel_credentials) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "credentials must be a ChannelCredentials object",
-                           1);
-      return;
-    } else {
       creds = Z_WRAPPED_GRPC_CHANNEL_CREDS_P(creds_obj);
-      zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
+      php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
     }
   }
-#endif
   php_grpc_read_args_array(args_array, &args TSRMLS_CC);
   if (creds == NULL) {
     channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
@@ -292,8 +225,7 @@
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
           &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-        "watchConnectivityState expects 1 long 1 timeval",
-        1 TSRMLS_CC);
+        "watchConnectivityState expects 1 long 1 timeval", 1 TSRMLS_CC);
     return;
   }
 
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index cef435c..32f24e5 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -77,16 +77,7 @@
  * associated with an object of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_channel_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  wrapped_grpc_channel_credentials *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_channel_credentials *)emalloc(
-      sizeof(wrapped_grpc_channel_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_channel_credentials));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_channel_credentials) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7
diff --git a/src/php/ext/grpc/php7_wrapper.h b/src/php/ext/grpc/php7_wrapper.h
index 7d7470f..ba7f163 100644
--- a/src/php/ext/grpc/php7_wrapper.h
+++ b/src/php/ext/grpc/php7_wrapper.h
@@ -50,6 +50,7 @@
 
 #define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val, dup)
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) MAKE_STD_ZVAL(pzv)
+#define PHP_GRPC_DELREF(zv) Z_DELREF_P(zv)
 
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
   typedef struct name { \
@@ -65,6 +66,58 @@
     efree(p); \
   }
 
+#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
+  class_object *intern; \
+  zend_object_value retval; \
+  intern = (class_object *)emalloc(sizeof(class_object)); \
+  memset(intern, 0, sizeof(class_object));
+
+#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
+  zval **tmp_data = NULL; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp_data) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    data = *tmp_data;
+
+#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
+  zval **tmp##key = NULL; \
+  ulong index##key; \
+  uint len##key; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index##key,\
+                                         0, NULL); \
+    data = *tmp##key;
+
+#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index,\
+                                                 data) \
+  zval **tmp##key = NULL; \
+  uint len##key; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index,\
+                                         0, NULL); \
+    data = *tmp##key;
+
+#define PHP_GRPC_HASH_FOREACH_END() }
+
+static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len, void **value) {
+  zval **data = NULL;
+  if (zend_hash_find(ht, key, len, (void **)&data) == SUCCESS) {
+    *value = *data;
+    return SUCCESS;
+  } else {
+    *value = NULL;
+    return FAILURE;
+  }
+}
+
+#define php_grpc_zend_hash_del zend_hash_del
+
+#define PHP_GRPC_GET_CLASS_ENTRY(object) zend_get_class_entry(object TSRMLS_CC)
+
 #else
 
 #define php_grpc_int size_t
@@ -82,6 +135,7 @@
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
   zval _stack_zval_##pzv; \
   pzv = &(_stack_zval_##pzv)
+#define PHP_GRPC_DELREF(zv)
 
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
   typedef struct name {
@@ -99,6 +153,45 @@
     zend_object_std_dtor(&p->std); \
   }
 
+#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
+  class_object *intern; \
+  intern = ecalloc(1, sizeof(class_object) + \
+                   zend_object_properties_size(class_type));
+
+#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
+  ZEND_HASH_FOREACH_VAL(ht, data) {
+
+#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
+  zend_string *(zs_##key); \
+  ZEND_HASH_FOREACH_STR_KEY_VAL(ht, (zs_##key), data) { \
+    if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
+    else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
+
+#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index, \
+                                                 data) \
+  zend_string *(zs_##key); \
+  ZEND_HASH_FOREACH_KEY_VAL(ht, index, zs_##key, data) { \
+    if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
+    else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
+
+#define PHP_GRPC_HASH_FOREACH_END() } ZEND_HASH_FOREACH_END();
+
+static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len, void **value) {
+  zval *value_tmp = zend_hash_str_find(ht, key, len -1);
+  if (value_tmp == NULL) {
+    return FAILURE;
+  } else {
+    *value = (void *)value_tmp;
+    return SUCCESS;
+  }
+}
+
+static inline int php_grpc_zend_hash_del(HashTable *ht, char *key, int len) {
+  return zend_hash_str_del(ht, key, len - 1);
+}
+
+#define PHP_GRPC_GET_CLASS_ENTRY(object) Z_OBJ_P(object)->ce
+
 #endif /* PHP_MAJOR_VERSION */
 
 #endif /* PHP7_WRAPPER_GRPC_H */
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index d8ebd44..2fc785e 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -76,15 +76,7 @@
  * of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_server(zend_class_entry *class_type
                                                 TSRMLS_DC) {
-  wrapped_grpc_server *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_server *)emalloc(sizeof(wrapped_grpc_server));
-  memset(intern, 0, sizeof(wrapped_grpc_server));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_server) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 921436a..4c147e0 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -65,16 +65,7 @@
  * with an object of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_server_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  wrapped_grpc_server_credentials *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_server_credentials *)emalloc(
-      sizeof(wrapped_grpc_server_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_server_credentials));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_server_credentials) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 33d11f8..d0f75be 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -63,15 +63,7 @@
  * object of a class specified by class_type */
 php_grpc_zend_object create_wrapped_grpc_timeval(zend_class_entry *class_type
                                                  TSRMLS_DC) {
-  wrapped_grpc_timeval *intern;
-#if PHP_MAJOR_VERSION < 7
-  zend_object_value retval;
-  intern = (wrapped_grpc_timeval *)emalloc(sizeof(wrapped_grpc_timeval));
-  memset(intern, 0, sizeof(wrapped_grpc_timeval));
-#else
-  intern = ecalloc(1, sizeof(wrapped_grpc_timeval) +
-                   zend_object_properties_size(class_type));
-#endif
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_timeval);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
 #if PHP_MAJOR_VERSION < 7