From a3730b75f8cf086f7eedc2f34ad6d928b69b28d0 Mon Sep 17 00:00:00 2001
From: thinkerou <thinkerou@gmail.com>
Date: Wed, 20 Jul 2016 16:59:54 +0800
Subject: [PATCH] support php7 by marco

---
 src/php/ext/grpc/call.c                       | 692 +++++++++++++-----
 src/php/ext/grpc/call.h                       |  36 +-
 src/php/ext/grpc/call_credentials.c           | 103 ++-
 src/php/ext/grpc/call_credentials.h           |  23 +
 src/php/ext/grpc/channel.c                    | 191 ++++-
 src/php/ext/grpc/channel.h                    |  23 +-
 src/php/ext/grpc/channel_credentials.c        |  89 ++-
 src/php/ext/grpc/channel_credentials.h        |  23 +
 src/php/ext/grpc/php_grpc.c                   |  54 +-
 src/php/ext/grpc/php_grpc.h                   |   4 +-
 src/php/ext/grpc/server.c                     | 136 +++-
 src/php/ext/grpc/server.h                     |  20 +
 src/php/ext/grpc/server_credentials.c         |  64 +-
 src/php/ext/grpc/server_credentials.h         |  20 +
 src/php/ext/grpc/timeval.c                    | 138 +++-
 src/php/ext/grpc/timeval.h                    |  23 +
 src/php/lib/Grpc/BaseStub.php                 |   4 +-
 src/php/lib/Grpc/BidiStreamingCall.php        |   1 +
 src/php/lib/Grpc/ClientStreamingCall.php      |   1 +
 src/php/lib/Grpc/ServerStreamingCall.php      |   1 +
 src/php/lib/Grpc/UnaryCall.php                |   1 +
 src/php/tests/unit_tests/CallTest.php         |  47 ++
 .../unit_tests/ChannelCredentialsTest.php     |  24 +-
 src/php/tests/unit_tests/ChannelTest.php      | 107 +++
 src/php/tests/unit_tests/EndToEndTest.php     |   0
 .../tests/unit_tests/SecureEndToEndTest.php   |   0
 src/php/tests/unit_tests/ServerTest.php       | 142 +++-
 src/php/tests/unit_tests/TimevalTest.php      |  53 ++
 28 files changed, 1726 insertions(+), 294 deletions(-)
 mode change 100755 => 100644 src/php/lib/Grpc/BaseStub.php
 mode change 100755 => 100644 src/php/tests/unit_tests/CallTest.php
 mode change 100755 => 100644 src/php/tests/unit_tests/EndToEndTest.php
 mode change 100755 => 100644 src/php/tests/unit_tests/SecureEndToEndTest.php
 mode change 100755 => 100644 src/php/tests/unit_tests/TimevalTest.php

diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 2cd45f10dc..bd1eccb01b 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -59,12 +59,15 @@
 
 zend_class_entry *grpc_ce_call;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instance of wrapped_grpc_call */
 void free_wrapped_grpc_call(void *object TSRMLS_DC) {
   wrapped_grpc_call *call = (wrapped_grpc_call *)object;
   if (call->owned && call->wrapped != NULL) {
     grpc_call_destroy(call->wrapped);
   }
+  zend_object_std_dtor(&call->std TSRMLS_CC);
   efree(call);
 }
 
@@ -203,6 +206,131 @@ bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
   return true;
 }
 
+#else
+
+static zend_object_handlers call_ce_handlers;
+
+/* Frees and destroys an instance of wrapped_grpc_call */
+static void free_wrapped_grpc_call(zend_object *object) {
+  wrapped_grpc_call *call = wrapped_grpc_call_from_obj(object);
+  if (call->owned && call->wrapped != NULL) {
+    grpc_call_destroy(call->wrapped);
+  }
+  zend_object_std_dtor(&call->std);
+}
+
+/* Initializes an instance of wrapped_grpc_call to be associated with an
+ * object of a class specified by class_type */
+zend_object *create_wrapped_grpc_call(zend_class_entry *class_type) {
+  wrapped_grpc_call *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_call) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &call_ce_handlers;
+  return &intern->std;
+}
+
+/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the
+   struct should be destroyed at the end of the object's lifecycle */
+void grpc_php_wrap_call(grpc_call *wrapped, bool owned, zval *call_object) {
+  object_init_ex(call_object, grpc_ce_call);
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(call_object);
+  call->wrapped = wrapped;
+  call->owned = owned;
+}
+
+/* Creates and returns a PHP array object with the data in a
+ * grpc_metadata_array. Returns NULL on failure */
+void grpc_parse_metadata_array(grpc_metadata_array *metadata_array,
+                               zval *array) {
+  int count = metadata_array->count;
+  grpc_metadata *elements = metadata_array->metadata;
+  int i;
+  zval *data;
+  HashTable *array_hash;
+  zval inner_array;
+  char *str_key;
+  char *str_val;
+  size_t key_len;
+
+  array_init(array);
+  array_hash = HASH_OF(array);
+  grpc_metadata *elem;
+  for (i = 0; i < count; i++) {
+    elem = &elements[i];
+    key_len = strlen(elem->key);
+    str_key = ecalloc(key_len + 1, sizeof(char));
+    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 ((data = zend_hash_str_find(array_hash, str_key, key_len)) != NULL) {
+      if (Z_TYPE_P(data) != IS_ARRAY) {
+        zend_throw_exception(zend_exception_get_default(),
+                             "Metadata hash somehow contains wrong types.",
+                             1);
+        efree(str_key);
+        efree(str_val);
+        return;
+      }
+      add_next_index_stringl(data, str_val, elem->value_length);
+    } else {
+      array_init(&inner_array);
+      add_next_index_stringl(&inner_array, str_val, elem->value_length);
+      add_assoc_zval(array, str_key, &inner_array);
+    }
+  }
+}
+
+/* Populates a grpc_metadata_array with the data in a PHP array object.
+   Returns true on success and false on failure */
+bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
+  zval *inner_array;
+  zval *value;
+  HashTable *array_hash;
+  HashTable *inner_array_hash;
+  zend_string *key;
+  if (Z_TYPE_P(array) != IS_ARRAY) {
+    return false;
+  }
+  grpc_metadata_array_init(metadata);
+  array_hash = HASH_OF(array);
+
+  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
+    if (key == NULL) {
+      return false;
+    }
+    if (Z_TYPE_P(inner_array) != IS_ARRAY) {
+      return false;
+    }
+    inner_array_hash = HASH_OF(inner_array);
+    metadata->capacity += zend_hash_num_elements(inner_array_hash);
+  }
+  ZEND_HASH_FOREACH_END();
+
+  metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
+
+  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) {
+      if (Z_TYPE_P(value) != IS_STRING) {
+        return false;
+      }
+      metadata->metadata[metadata->count].key = ZSTR_VAL(key);
+      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();
+  return true;
+}
+
+#endif
+
 /**
  * Constructs a new instance of the Call class.
  * @param Channel $channel The channel to associate the call with. Must not be
@@ -211,30 +339,38 @@ bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
  * @param Timeval $absolute_deadline The deadline for completing the call
  */
 PHP_METHOD(Call, __construct) {
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
   zval *channel_obj;
   char *method;
-  int method_len;
   zval *deadline_obj;
   char *host_override = NULL;
+#if PHP_MAJOR_VERSION < 7
+  int method_len;
   int host_override_len = 0;
+  wrapped_grpc_call *call =
+      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  size_t method_len;
+  size_t host_override_len = 0;
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
+#endif
+
   /* "OsO|s" == 1 Object, 1 string, 1 Object, 1 optional string */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s",
-                            &channel_obj, grpc_ce_channel,
-                            &method, &method_len,
-                            &deadline_obj, grpc_ce_timeval,
-                            &host_override, &host_override_len)
-      == FAILURE) {
-    zend_throw_exception(
-        spl_ce_InvalidArgumentException,
-        "Call expects a Channel, a String, a Timeval and an optional String",
-        1 TSRMLS_CC);
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO|s", &channel_obj,
+                            grpc_ce_channel, &method, &method_len,
+                            &deadline_obj, grpc_ce_timeval, &host_override,
+                            &host_override_len) == FAILURE) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+                         "Call expects a Channel, a String, a Timeval and "
+                         "an optional String", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_channel *channel =
       (wrapped_grpc_channel *)zend_object_store_get_object(
           channel_obj TSRMLS_CC);
+#else
+  wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(channel_obj);
+#endif
   if (channel->wrapped == NULL) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "Call cannot be constructed from a closed Channel",
@@ -242,12 +378,17 @@ PHP_METHOD(Call, __construct) {
     return;
   }
   add_property_zval(getThis(), "channel", channel_obj);
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *deadline =
       (wrapped_grpc_timeval *)zend_object_store_get_object(
           deadline_obj TSRMLS_CC);
-  call->wrapped = grpc_channel_create_call(
-      channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS, completion_queue, method,
-      host_override, deadline->wrapped, NULL);
+#else
+  wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
+#endif
+  call->wrapped =
+    grpc_channel_create_call(channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS,
+                             completion_queue, method, host_override,
+                             deadline->wrapped, NULL);
   call->owned = true;
 }
 
@@ -257,22 +398,40 @@ PHP_METHOD(Call, __construct) {
  * @return object Object with results of all actions
  */
 PHP_METHOD(Call, startBatch) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  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;
   char *key;
   uint key_len;
   ulong index;
+  zval *result;
+  zval *recv_status;
+  MAKE_STD_ZVAL(result);
+  object_init(result);
+#else
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
+  zval *value;
+  zval *inner_value;
+  zval *message_value;
+  zval *message_flags;
+  zend_string *key;
+  zend_ulong index;
+  zval recv_status;
+  object_init(return_value);
+#endif
+  
+  grpc_op ops[8];
+  size_t op_num = 0;
+  zval *array;
+  HashTable *array_hash;
+  HashTable *status_hash;
+  HashTable *message_hash;
+
   grpc_metadata_array metadata;
   grpc_metadata_array trailing_metadata;
   grpc_metadata_array recv_metadata;
@@ -283,17 +442,16 @@ PHP_METHOD(Call, startBatch) {
   grpc_byte_buffer *message;
   int cancelled;
   grpc_call_error error;
-  zval *result;
   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);
-  MAKE_STD_ZVAL(result);
-  object_init(result);
   memset(ops, 0, sizeof(ops));
+  
   /* "a" == 1 array */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
       FAILURE) {
@@ -301,6 +459,9 @@ PHP_METHOD(Call, startBatch) {
                          "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,
@@ -313,124 +474,250 @@ PHP_METHOD(Call, startBatch) {
       goto cleanup;
     }
     switch(index) {
-      case GRPC_OP_SEND_INITIAL_METADATA:
-        if (!create_metadata_array(*value, &metadata)) {
+    case GRPC_OP_SEND_INITIAL_METADATA:
+      if (!create_metadata_array(*value, &metadata)) {
+        zend_throw_exception(spl_ce_InvalidArgumentException,
+                             "Bad metadata value given", 1 TSRMLS_CC);
+        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_PP(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"),
+                         (void **)&message_flags) == SUCCESS) {
+        if (Z_TYPE_PP(message_flags) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Bad metadata value given", 1 TSRMLS_CC);
-          goto cleanup;
+                               "Expected an int for message flags",
+                               1 TSRMLS_CC);
         }
-        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_PP(value) != IS_ARRAY) {
+        ops[op_num].flags = Z_LVAL_PP(message_flags) & GRPC_WRITE_USED_MASK;
+      }
+      if (zend_hash_find(message_hash, "message", sizeof("message"),
+                         (void **)&message_value) != SUCCESS ||
+          Z_TYPE_PP(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));
+      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"),
+                         (void **)&inner_value) == SUCCESS) {
+        if (!create_metadata_array(*inner_value, &trailing_metadata)) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Expected an array for send message",
+                               "Bad trailing metadata value given",
                                1 TSRMLS_CC);
           goto cleanup;
         }
-        message_hash = Z_ARRVAL_PP(value);
-        if (zend_hash_find(message_hash, "flags", sizeof("flags"),
-                           (void **)&message_flags) == SUCCESS) {
-          if (Z_TYPE_PP(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].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 (zend_hash_find(status_hash, "code", sizeof("code"),
+                         (void**)&inner_value) == SUCCESS) {
+        if (Z_TYPE_PP(inner_value) != IS_LONG) {
+          zend_throw_exception(spl_ce_InvalidArgumentException,
+                               "Status code must be an integer",
+                               1 TSRMLS_CC);
+          goto cleanup;
         }
-        if (zend_hash_find(message_hash, "message", sizeof("message"),
-                           (void **)&message_value) != SUCCESS ||
-            Z_TYPE_PP(message_value) != IS_STRING) {
+        ops[op_num].data.send_status_from_server.status =
+            Z_LVAL_PP(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"),
+                         (void**)&inner_value) == SUCCESS) {
+        if (Z_TYPE_PP(inner_value) != IS_STRING) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Expected a string for send message",
+                               "Status details must be a string",
                                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));
-        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"),
-                           (void **)&inner_value) == SUCCESS) {
-          if (!create_metadata_array(*inner_value, &trailing_metadata)) {
-            zend_throw_exception(spl_ce_InvalidArgumentException,
-                                 "Bad trailing metadata value given",
-                                 1 TSRMLS_CC);
-            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;
+        ops[op_num].data.send_status_from_server.status_details =
+            Z_STRVAL_PP(inner_value);
+      } else {
+        zend_throw_exception(spl_ce_InvalidArgumentException,
+                             "String status details is required",
+                             1 TSRMLS_CC);
+        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 TSRMLS_CC);
+      goto cleanup;
+    }
+    ops[op_num].op = (grpc_op_type)index;
+    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;
         }
-        if (zend_hash_find(status_hash, "code", sizeof("code"),
-                           (void**)&inner_value) == SUCCESS) {
-          if (Z_TYPE_PP(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);
-        } else {
+        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,
-                               "Integer status code is required",
-                               1 TSRMLS_CC);
+                               "Status code must be an integer", 1);
           goto cleanup;
         }
-        if (zend_hash_find(status_hash, "details", sizeof("details"),
-                           (void**)&inner_value) == SUCCESS) {
-          if (Z_TYPE_PP(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);
-        } else {
+        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,
-                               "String status details is required",
-                               1 TSRMLS_CC);
+                               "Status details must be a string", 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:
+        ops[op_num].data.send_status_from_server.status_details =
+          Z_STRVAL_P(inner_value);
+      } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Unrecognized key in batch", 1 TSRMLS_CC);
+                             "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
+
   error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
                                 NULL);
   if (error != GRPC_CALL_OK) {
@@ -441,52 +728,98 @@ PHP_METHOD(Call, startBatch) {
   }
   grpc_completion_queue_pluck(completion_queue, call->wrapped,
                               gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+#if PHP_MAJOR_VERSION < 7
   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:
-        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;
+    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:
+      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
+  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);
+      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);
+      add_property_long(&recv_status, "code", status);
+      add_property_string(&recv_status, "details", status_details);
+      add_property_zval(return_value, "status", &recv_status);
+      break;
+    case GRPC_OP_RECV_CLOSE_ON_SERVER:
+      add_property_bool(return_value, "cancelled", cancelled);
+      break;
+    default:
+      break;
     }
   }
+#endif
+
 cleanup:
   grpc_metadata_array_destroy(&metadata);
   grpc_metadata_array_destroy(&trailing_metadata);
@@ -503,7 +836,11 @@ cleanup:
       grpc_byte_buffer_destroy(message);
     }
   }
+#if PHP_MAJOR_VERSION < 7
   RETURN_DESTROY_ZVAL(result);
+#else
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -511,9 +848,14 @@ cleanup:
  * @return string The URI of the endpoint
  */
 PHP_METHOD(Call, getPeer) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
   RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
+#else
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
+  RETURN_STRING(grpc_call_get_peer(call->wrapped));
+#endif
 }
 
 /**
@@ -521,8 +863,12 @@ PHP_METHOD(Call, getPeer) {
  * has not already ended with another status.
  */
 PHP_METHOD(Call, cancel) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
+#endif
   grpc_call_cancel(call->wrapped, NULL);
 }
 
@@ -543,12 +889,17 @@ PHP_METHOD(Call, setCredentials) {
     return;
   }
 
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_call_credentials *creds =
       (wrapped_grpc_call_credentials *)zend_object_store_get_object(
           creds_obj TSRMLS_CC);
-
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  wrapped_grpc_call_credentials *creds =
+    Z_WRAPPED_GRPC_CALL_CREDS_P(creds_obj);
+  wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
+#endif
 
   grpc_call_error error = GRPC_CALL_ERROR;
   error = grpc_call_set_credentials(call->wrapped, creds->wrapped);
@@ -556,16 +907,23 @@ PHP_METHOD(Call, setCredentials) {
 }
 
 static zend_function_entry call_methods[] = {
-    PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, setCredentials, NULL, ZEND_ACC_PUBLIC)
-    PHP_FE_END};
+  PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+  PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Call, setCredentials, NULL, ZEND_ACC_PUBLIC)
+  PHP_FE_END
+};
 
 void grpc_init_call(TSRMLS_D) {
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\Call", call_methods);
   ce.create_object = create_wrapped_grpc_call;
   grpc_ce_call = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&call_ce_handlers, zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  call_ce_handlers.offset = XtOffsetOf(wrapped_grpc_call, std);
+  call_ce_handlers.free_obj = free_wrapped_grpc_call;
+#endif
 }
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index 36c5f2d272..9fc52d7820 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -48,17 +48,15 @@
 /* Class entry for the Call PHP class */
 extern zend_class_entry *grpc_ce_call;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Wrapper struct for grpc_call that can be associated with a PHP object */
 typedef struct wrapped_grpc_call {
   zend_object std;
-
   bool owned;
   grpc_call *wrapped;
 } wrapped_grpc_call;
 
-/* Initializes the Call PHP class */
-void grpc_init_call(TSRMLS_D);
-
 /* Creates a Call object that wraps the given grpc_call struct */
 zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
 
@@ -66,6 +64,36 @@ zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned TSRMLS_DC);
  * call metadata */
 zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array TSRMLS_DC);
 
+#else
+
+/* Wrapper struct for grpc_call that can be associated with a PHP object */
+typedef struct wrapped_grpc_call {
+  bool owned;
+  grpc_call *wrapped;
+  zend_object std;
+} wrapped_grpc_call;
+
+static inline wrapped_grpc_call
+*wrapped_grpc_call_from_obj(zend_object *obj) {
+  return (wrapped_grpc_call*)((char*)(obj) -
+                              XtOffsetOf(wrapped_grpc_call, std));
+}
+
+#define Z_WRAPPED_GRPC_CALL_P(zv) wrapped_grpc_call_from_obj(Z_OBJ_P((zv)))
+
+/* Creates a Call object that wraps the given grpc_call struct */
+void grpc_php_wrap_call(grpc_call *wrapped, bool owned, zval *call_object);
+
+/* Creates and returns a PHP associative array of metadata from a C array of
+ * call metadata */
+void grpc_parse_metadata_array(grpc_metadata_array *metadata_array,
+                               zval *array);
+
+#endif /* PHP_MAJOR_VERSION */
+
+/* Initializes the Call PHP class */
+void grpc_init_call(TSRMLS_D);
+
 /* Populates a grpc_metadata_array with the data in a PHP array object.
    Returns true on success and false on failure */
 bool create_metadata_array(zval *array, grpc_metadata_array *metadata);
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index ec0e6b9181..70aaffb848 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -53,6 +53,8 @@
 
 zend_class_entry *grpc_ce_call_credentials;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instance of wrapped_grpc_call_credentials */
 void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) {
   wrapped_grpc_call_credentials *creds =
@@ -60,6 +62,7 @@ void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) {
   if (creds->wrapped != NULL) {
     grpc_call_credentials_release(creds->wrapped);
   }
+  zend_object_std_dtor(&creds->std TSRMLS_CC);
   efree(creds);
 }
 
@@ -94,6 +97,43 @@ zval *grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped TSRMLS_DC) {
   return credentials_object;
 }
 
+#else
+
+static zend_object_handlers call_credentials_ce_handlers;
+
+/* Frees and destroys an instance of wrapped_grpc_call_credentials */
+static void free_wrapped_grpc_call_credentials(zend_object *object) {
+  wrapped_grpc_call_credentials *creds =
+    wrapped_grpc_call_creds_from_obj(object);
+  if (creds->wrapped != NULL) {
+    grpc_call_credentials_release(creds->wrapped);
+  }
+  zend_object_std_dtor(&creds->std);
+}
+
+/* Initializes an instance of wrapped_grpc_call_credentials to be
+ * associated with an object of a class specified by class_type */
+zend_object *create_wrapped_grpc_call_credentials(zend_class_entry
+                                                  *class_type) {
+  wrapped_grpc_call_credentials *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_call_credentials) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &call_credentials_ce_handlers;
+  return &intern->std;
+}
+
+void grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped,
+                                    zval *credentials_object) {
+  object_init_ex(credentials_object, grpc_ce_call_credentials);
+  wrapped_grpc_call_credentials *credentials =
+    Z_WRAPPED_GRPC_CALL_CREDS_P(credentials_object);
+  credentials->wrapped = wrapped;
+}
+
+#endif
+
 /**
  * Create composite credentials from two existing credentials.
  * @param CallCredentials cred1 The first credential
@@ -113,6 +153,7 @@ PHP_METHOD(CallCredentials, createComposite) {
                          1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_call_credentials *cred1 =
       (wrapped_grpc_call_credentials *)zend_object_store_get_object(
           cred1_obj TSRMLS_CC);
@@ -124,6 +165,17 @@ PHP_METHOD(CallCredentials, createComposite) {
                                              NULL);
   zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
+#else
+  wrapped_grpc_call_credentials *cred1 =
+    Z_WRAPPED_GRPC_CALL_CREDS_P(cred1_obj);
+  wrapped_grpc_call_credentials *cred2 =
+    Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
+  grpc_call_credentials *creds =
+    grpc_composite_call_credentials_create(cred1->wrapped,
+                                           cred2->wrapped, NULL);
+  grpc_php_wrap_call_credentials(creds, return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -141,13 +193,10 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
   memset(fci_cache, 0, sizeof(zend_fcall_info_cache));
 
   /* "f" == 1 function */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f", fci,
-                            fci_cache,
-                            fci->params,
-                            fci->param_count) == FAILURE) {
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f*", fci, fci_cache,
+                            fci->params, fci->param_count) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "createFromPlugin expects 1 callback",
-                         1 TSRMLS_CC);
+                         "createFromPlugin expects 1 callback", 1 TSRMLS_CC);
     return;
   }
 
@@ -165,10 +214,15 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
   plugin.state = (void *)state;
   plugin.type = "";
 
-  grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin(
-      plugin, NULL);
+  grpc_call_credentials *creds =
+    grpc_metadata_credentials_create_from_plugin(plugin, NULL);
+#if PHP_MAJOR_VERSION < 7
   zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
+#else
+  grpc_php_wrap_call_credentials(creds, return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /* Callback function for plugin creds API */
@@ -181,6 +235,7 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
 
   /* prepare to call the user callback function with info from the
    * grpc_auth_metadata_context */
+#if PHP_MAJOR_VERSION < 7
   zval **params[1];
   zval *arg;
   zval *retval;
@@ -192,21 +247,41 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
   state->fci->param_count = 1;
   state->fci->params = params;
   state->fci->retval_ptr_ptr = &retval;
+#else
+  zval arg;
+  zval retval;
+  object_init(&arg);
+  add_property_string(&arg, "service_url", context.service_url);
+  add_property_string(&arg, "method_name", context.method_name);
+  state->fci->param_count = 1;
+  state->fci->params = &arg;
+  state->fci->retval = &retval;
+#endif
 
   /* call the user callback function */
   zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
 
+#if PHP_MAJOR_VERSION < 7
   if (Z_TYPE_P(retval) != IS_ARRAY) {
+#else
+  if (Z_TYPE_P(&retval) != IS_ARRAY) {
+#endif
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "plugin callback must return metadata array",
                          1 TSRMLS_CC);
+    return;
   }
 
   grpc_metadata_array metadata;
+#if PHP_MAJOR_VERSION < 7
   if (!create_metadata_array(retval, &metadata)) {
+#else
+  if (!create_metadata_array(&retval, &metadata)) {
+#endif
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "invalid metadata", 1 TSRMLS_CC);
     grpc_metadata_array_destroy(&metadata);
+    return;
   }
 
   /* TODO: handle error */
@@ -229,11 +304,21 @@ static zend_function_entry call_credentials_methods[] = {
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
   PHP_ME(CallCredentials, createFromPlugin, NULL,
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-  PHP_FE_END};
+  PHP_FE_END
+};
 
 void grpc_init_call_credentials(TSRMLS_D) {
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
   ce.create_object = create_wrapped_grpc_call_credentials;
   grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&call_credentials_ce_handlers,
+         zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  call_credentials_ce_handlers.offset =
+    XtOffsetOf(wrapped_grpc_call_credentials, std);
+  call_credentials_ce_handlers.free_obj =
+    free_wrapped_grpc_call_credentials;
+#endif
 }
diff --git a/src/php/ext/grpc/call_credentials.h b/src/php/ext/grpc/call_credentials.h
index d2f6a92449..e05e14698b 100755
--- a/src/php/ext/grpc/call_credentials.h
+++ b/src/php/ext/grpc/call_credentials.h
@@ -49,14 +49,37 @@
 /* Class entry for the CallCredentials PHP class */
 extern zend_class_entry *grpc_ce_call_credentials;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Wrapper struct for grpc_call_credentials that can be associated
  * with a PHP object */
 typedef struct wrapped_grpc_call_credentials {
   zend_object std;
+  grpc_call_credentials *wrapped;
+} wrapped_grpc_call_credentials;
 
+#else
+
+/* Wrapper struct for grpc_call_credentials that can be associated
+ * with a PHP object */
+typedef struct wrapped_grpc_call_credentials {
   grpc_call_credentials *wrapped;
+  zend_object std;
 } wrapped_grpc_call_credentials;
 
+static inline wrapped_grpc_call_credentials
+*wrapped_grpc_call_creds_from_obj(zend_object *obj) {
+  return
+    (wrapped_grpc_call_credentials*)((char*)(obj) -
+                                     XtOffsetOf(wrapped_grpc_call_credentials,
+                                                std));
+}
+
+#define Z_WRAPPED_GRPC_CALL_CREDS_P(zv)           \
+  wrapped_grpc_call_creds_from_obj(Z_OBJ_P((zv)))
+
+#endif /* PHP_MAJOR_VERSION */
+
 /* Struct to hold callback function for plugin creds API */
 typedef struct plugin_state {
   zend_fcall_info *fci;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 8d94c59683..ce96457c7c 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -57,12 +57,15 @@
 
 zend_class_entry *grpc_ce_channel;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instance of wrapped_grpc_channel */
 void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
   wrapped_grpc_channel *channel = (wrapped_grpc_channel *)object;
   if (channel->wrapped != NULL) {
     grpc_channel_destroy(channel->wrapped);
   }
+  zend_object_std_dtor(&channel->std TSRMLS_CC);
   efree(channel);
 }
 
@@ -107,23 +110,88 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_D
     }
     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;
+    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
+
+static zend_object_handlers channel_ce_handlers;
+
+/* Frees and destroys an instance of wrapped_grpc_channel */
+static void free_wrapped_grpc_channel(zend_object *object) {
+  wrapped_grpc_channel *channel = wrapped_grpc_channel_from_obj(object);
+  if (channel->wrapped != NULL) {
+    grpc_channel_destroy(channel->wrapped);
+  }
+  zend_object_std_dtor(&channel->std);
+}
+
+/* Initializes an instance of wrapped_grpc_channel to be associated with an
+ * object of a class specified by class_type */
+zend_object *create_wrapped_grpc_channel(zend_class_entry *class_type) {
+  wrapped_grpc_channel *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_channel) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &channel_ce_handlers;
+  return &intern->std;
+}
+
+void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args) {
+  HashTable *array_hash;
+  int args_index;
+  zval *data;
+  zend_string *key;
+  array_hash = HASH_OF(args_array);
+  if (!array_hash) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+                         "array_hash is NULL", 1);
+    return;
+  }
+  args->num_args = zend_hash_num_elements(array_hash);
+  args->args = ecalloc(args->num_args, sizeof(grpc_arg));
+  args_index = 0;
+  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);
+      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);
+      return;
+    }
+    args_index++;
+  } ZEND_HASH_FOREACH_END();
+}
+
+#endif
+
 /**
  * Construct an instance of the Channel class. If the $args array contains a
  * "credentials" key mapping to a ChannelCredentials object, a secure channel
@@ -132,16 +200,23 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_D
  * @param array $args The arguments to pass to the Channel (optional)
  */
 PHP_METHOD(Channel, __construct) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_channel *channel =
       (wrapped_grpc_channel *)zend_object_store_get_object(
           getThis() TSRMLS_CC);
-  char *target;
+  zval **creds_obj = NULL;
   int target_length;
+#else
+  wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
+  zval *creds_obj = NULL;
+  size_t target_length;
+#endif
+  char *target;
   zval *args_array = NULL;
   grpc_channel_args args;
   HashTable *array_hash;
-  zval **creds_obj = NULL;
   wrapped_grpc_channel_credentials *creds = NULL;
+
   /* "sa" == 1 string, 1 array */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &target,
                             &target_length, &args_array) == FAILURE) {
@@ -149,6 +224,7 @@ PHP_METHOD(Channel, __construct) {
                          "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"),
                      (void **)&creds_obj) == SUCCESS) {
@@ -167,6 +243,24 @@ PHP_METHOD(Channel, __construct) {
       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);
+    }
+  }
+#endif
   php_grpc_read_args_array(args_array, &args TSRMLS_CC);
   if (creds == NULL) {
     channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
@@ -182,9 +276,14 @@ PHP_METHOD(Channel, __construct) {
  * @return string The URI of the endpoint
  */
 PHP_METHOD(Channel, getTarget) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+    (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
   RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
+#else
+  wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
+  RETURN_STRING(grpc_channel_get_target(channel->wrapped));
+#endif
 }
 
 /**
@@ -193,12 +292,17 @@ PHP_METHOD(Channel, getTarget) {
  * @return long The grpc connectivity state
  */
 PHP_METHOD(Channel, getConnectivityState) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_channel *channel =
       (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  bool try_to_connect;
+#else
+  wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
+#endif
+  bool try_to_connect = false;
+
   /* "|b" == 1 optional bool */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect) ==
-      FAILURE) {
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect)
+      == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "getConnectivityState expects a bool", 1 TSRMLS_CC);
     return;
@@ -215,10 +319,16 @@ PHP_METHOD(Channel, getConnectivityState) {
  *              before deadline
  */
 PHP_METHOD(Channel, watchConnectivityState) {
+#if PHP_MAJOR_VERSION < 7
+  long last_state;
   wrapped_grpc_channel *channel =
       (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  long last_state;
+#else
+  zend_long last_state;
+  wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
+#endif
   zval *deadline_obj;
+
   /* "lO" == 1 long 1 object */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
           &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
@@ -228,15 +338,20 @@ PHP_METHOD(Channel, watchConnectivityState) {
     return;
   }
 
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *deadline =
       (wrapped_grpc_timeval *)zend_object_store_get_object(
           deadline_obj TSRMLS_CC);
-  grpc_channel_watch_connectivity_state(
-      channel->wrapped, (grpc_connectivity_state)last_state,
-      deadline->wrapped, completion_queue, NULL);
-  grpc_event event = grpc_completion_queue_pluck(
-      completion_queue, NULL,
-      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+#else
+  wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
+#endif
+  grpc_channel_watch_connectivity_state(channel->wrapped,
+                                        (grpc_connectivity_state)last_state,
+                                        deadline->wrapped, completion_queue,
+                                        NULL);
+  grpc_event event =
+    grpc_completion_queue_pluck(completion_queue, NULL,
+                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   RETURN_BOOL(event.success);
 }
 
@@ -244,8 +359,12 @@ PHP_METHOD(Channel, watchConnectivityState) {
  * Close the channel
  */
 PHP_METHOD(Channel, close) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+    (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
+#endif
   if (channel->wrapped != NULL) {
     grpc_channel_destroy(channel->wrapped);
     channel->wrapped = NULL;
@@ -253,16 +372,24 @@ PHP_METHOD(Channel, close) {
 }
 
 static zend_function_entry channel_methods[] = {
-    PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Channel, getConnectivityState, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Channel, watchConnectivityState, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
-    PHP_FE_END};
+  PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+  PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Channel, getConnectivityState, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Channel, watchConnectivityState, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
+  PHP_FE_END
+};
 
 void grpc_init_channel(TSRMLS_D) {
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods);
   ce.create_object = create_wrapped_grpc_channel;
   grpc_ce_channel = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&channel_ce_handlers, zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  channel_ce_handlers.offset =
+    XtOffsetOf(wrapped_grpc_channel, std);
+  channel_ce_handlers.free_obj = free_wrapped_grpc_channel;
+#endif
 }
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index cc5823ee7f..ea5efeaf86 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -48,17 +48,38 @@
 /* Class entry for the PHP Channel class */
 extern zend_class_entry *grpc_ce_channel;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Wrapper struct for grpc_channel that can be associated with a PHP object */
 typedef struct wrapped_grpc_channel {
   zend_object std;
+  grpc_channel *wrapped;
+} wrapped_grpc_channel;
 
+#else
+
+/* Wrapper struct for grpc_channel that can be associated with a PHP object */
+typedef struct wrapped_grpc_channel {
   grpc_channel *wrapped;
+  zend_object std;
 } wrapped_grpc_channel;
 
+static inline wrapped_grpc_channel
+*wrapped_grpc_channel_from_obj(zend_object *obj) {
+  return (wrapped_grpc_channel*)((char*)(obj) -
+                                 XtOffsetOf(wrapped_grpc_channel, std));
+}
+
+#define Z_WRAPPED_GRPC_CHANNEL_P(zv)            \
+  wrapped_grpc_channel_from_obj(Z_OBJ_P((zv)))
+
+#endif /* PHP_MAJOR_VERSION */
+
 /* Initializes the Channel class */
 void grpc_init_channel(TSRMLS_D);
 
 /* Iterates through a PHP array and populates args with the contents */
-void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args TSRMLS_DC);
+void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args
+                              TSRMLS_DC);
 
 #endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index b76fb105f3..10e0acafac 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -52,7 +52,6 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_channel_credentials;
-
 static char *default_pem_root_certs = NULL;
 
 static grpc_ssl_roots_override_result get_ssl_roots_override(
@@ -64,6 +63,8 @@ static grpc_ssl_roots_override_result get_ssl_roots_override(
   return GRPC_SSL_ROOTS_OVERRIDE_OK;
 }
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instance of wrapped_grpc_channel_credentials */
 void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
   wrapped_grpc_channel_credentials *creds =
@@ -71,6 +72,7 @@ void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
   if (creds->wrapped != NULL) {
     grpc_channel_credentials_release(creds->wrapped);
   }
+  zend_object_std_dtor(&creds->std TSRMLS_CC);
   efree(creds);
 }
 
@@ -105,6 +107,43 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS
   return credentials_object;
 }
 
+#else
+
+static zend_object_handlers channel_credentials_ce_handlers;
+
+/* Frees and destroys an instance of wrapped_grpc_channel_credentials */
+static void free_wrapped_grpc_channel_credentials(zend_object *object) {
+  wrapped_grpc_channel_credentials *creds =
+    wrapped_grpc_channel_creds_from_obj(object);
+  if (creds->wrapped != NULL) {
+    grpc_channel_credentials_release(creds->wrapped);
+  }
+  zend_object_std_dtor(&creds->std);
+}
+
+/* Initializes an instance of wrapped_grpc_channel_credentials to be
+ * associated with an object of a class specified by class_type */
+zend_object *create_wrapped_grpc_channel_credentials(zend_class_entry
+                                                     *class_type) {
+  wrapped_grpc_channel_credentials *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_channel_credentials) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &channel_credentials_ce_handlers;
+  return &intern->std;
+}
+
+void grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped,
+                                       zval *credentials_object) {
+  object_init_ex(credentials_object, grpc_ce_channel_credentials);
+  wrapped_grpc_channel_credentials *credentials =
+    Z_WRAPPED_GRPC_CHANNEL_CREDS_P(credentials_object);
+  credentials->wrapped = wrapped;
+}
+
+#endif
+
 /**
  * Set default roots pem.
  * @param string pem_roots PEM encoding of the server root certificates
@@ -112,7 +151,13 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS
  */
 PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
   char *pem_roots;
+#if PHP_MAJOR_VERSION < 7
   int pem_roots_length;
+#else
+  size_t pem_roots_length;
+#endif
+
+  /* "s" == 1 string */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pem_roots,
                             &pem_roots_length) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
@@ -129,8 +174,13 @@ PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
  */
 PHP_METHOD(ChannelCredentials, createDefault) {
   grpc_channel_credentials *creds = grpc_google_default_credentials_create();
+#if PHP_MAJOR_VERSION < 7
   zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
+#else
+  grpc_php_wrap_channel_credentials(creds, return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -146,11 +196,15 @@ PHP_METHOD(ChannelCredentials, createSsl) {
   char *pem_root_certs = NULL;
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
 
+#if PHP_MAJOR_VERSION < 7
   int root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
+#else
+  size_t root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
+#endif
 
   pem_key_cert_pair.private_key = pem_key_cert_pair.cert_chain = NULL;
 
-  /* "|s!s!s! == 3 optional nullable strings */
+  /* "|s!s!s!" == 3 optional nullable strings */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!s!",
                             &pem_root_certs, &root_certs_length,
                             &pem_key_cert_pair.private_key,
@@ -164,8 +218,13 @@ PHP_METHOD(ChannelCredentials, createSsl) {
   grpc_channel_credentials *creds = grpc_ssl_credentials_create(
       pem_root_certs,
       pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
+#if PHP_MAJOR_VERSION < 7
   zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
+#else
+  grpc_php_wrap_channel_credentials(creds, return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -178,7 +237,7 @@ PHP_METHOD(ChannelCredentials, createComposite) {
   zval *cred1_obj;
   zval *cred2_obj;
 
-  /* "OO" == 3 Objects */
+  /* "OO" == 2 Objects */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
                             grpc_ce_channel_credentials, &cred2_obj,
                             grpc_ce_call_credentials) == FAILURE) {
@@ -186,6 +245,7 @@ PHP_METHOD(ChannelCredentials, createComposite) {
                          "createComposite expects 2 Credentials", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_channel_credentials *cred1 =
       (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
           cred1_obj TSRMLS_CC);
@@ -197,6 +257,17 @@ PHP_METHOD(ChannelCredentials, createComposite) {
                                                 NULL);
   zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
+#else
+  wrapped_grpc_channel_credentials *cred1 =
+    Z_WRAPPED_GRPC_CHANNEL_CREDS_P(cred1_obj);
+  wrapped_grpc_call_credentials *cred2 =
+    Z_WRAPPED_GRPC_CALL_CREDS_P(cred2_obj);
+  grpc_channel_credentials *creds =
+    grpc_composite_channel_credentials_create(cred1->wrapped,
+                                              cred2->wrapped, NULL);
+  grpc_php_wrap_channel_credentials(creds, return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -218,7 +289,8 @@ static zend_function_entry channel_credentials_methods[] = {
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
   PHP_ME(ChannelCredentials, createInsecure, NULL,
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-  PHP_FE_END};
+  PHP_FE_END
+};
 
 void grpc_init_channel_credentials(TSRMLS_D) {
   zend_class_entry ce;
@@ -227,4 +299,13 @@ void grpc_init_channel_credentials(TSRMLS_D) {
   grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
   ce.create_object = create_wrapped_grpc_channel_credentials;
   grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&channel_credentials_ce_handlers,
+         zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  channel_credentials_ce_handlers.offset =
+    XtOffsetOf(wrapped_grpc_channel_credentials, std);
+  channel_credentials_ce_handlers.free_obj =
+    free_wrapped_grpc_channel_credentials;
+#endif
 }
diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h
index d89984ce60..44071b10f1 100755
--- a/src/php/ext/grpc/channel_credentials.h
+++ b/src/php/ext/grpc/channel_credentials.h
@@ -49,14 +49,37 @@
 /* Class entry for the ChannelCredentials PHP class */
 extern zend_class_entry *grpc_ce_channel_credentials;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Wrapper struct for grpc_channel_credentials that can be associated
  * with a PHP object */
 typedef struct wrapped_grpc_channel_credentials {
   zend_object std;
+  grpc_channel_credentials *wrapped;
+} wrapped_grpc_channel_credentials;
 
+#else
+
+/* Wrapper struct for grpc_channel_credentials that can be associated
+ * with a PHP object */
+typedef struct wrapped_grpc_channel_credentials {
   grpc_channel_credentials *wrapped;
+  zend_object std;
 } wrapped_grpc_channel_credentials;
 
+static inline wrapped_grpc_channel_credentials
+*wrapped_grpc_channel_creds_from_obj(zend_object *obj) {
+  return
+    (wrapped_grpc_channel_credentials *)
+    ((char*)(obj) -
+     XtOffsetOf(wrapped_grpc_channel_credentials, std));
+}
+
+#define Z_WRAPPED_GRPC_CHANNEL_CREDS_P(zv)            \
+  wrapped_grpc_channel_creds_from_obj(Z_OBJ_P((zv)))
+
+#endif /* PHP_MAJOR_VERSION */
+
 /* Initializes the ChannelCredentials PHP class */
 void grpc_init_channel_credentials(TSRMLS_D);
 
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 449ba3cd47..5edfa2da7d 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -64,15 +64,19 @@ const zend_function_entry grpc_functions[] = {
  */
 zend_module_entry grpc_module_entry = {
 #if ZEND_MODULE_API_NO >= 20010901
-    STANDARD_MODULE_HEADER,
+  STANDARD_MODULE_HEADER,
 #endif
-    "grpc",                    grpc_functions, PHP_MINIT(grpc),
-    PHP_MSHUTDOWN(grpc),       NULL,           NULL,
-    PHP_MINFO(grpc),
+  "grpc",
+  grpc_functions,
+  PHP_MINIT(grpc),
+  PHP_MSHUTDOWN(grpc),
+  NULL,
+  NULL,
+  PHP_MINFO(grpc),
 #if ZEND_MODULE_API_NO >= 20010901
-    PHP_GRPC_VERSION,
+  PHP_GRPC_VERSION,
 #endif
-    STANDARD_MODULE_PROPERTIES};
+  STANDARD_MODULE_PROPERTIES};
 /* }}} */
 
 #ifdef COMPILE_DL_GRPC
@@ -82,23 +86,24 @@ ZEND_GET_MODULE(grpc)
 /* {{{ PHP_INI
  */
 /* Remove comments and fill if you need to have entries in php.ini
-PHP_INI_BEGIN()
-    STD_PHP_INI_ENTRY("grpc.global_value",      "42", PHP_INI_ALL, OnUpdateLong,
-global_value, zend_grpc_globals, grpc_globals)
-    STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL,
-OnUpdateString, global_string, zend_grpc_globals, grpc_globals)
-PHP_INI_END()
+   PHP_INI_BEGIN()
+   STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong,
+                     global_value, zend_grpc_globals, grpc_globals)
+   STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL,
+                     OnUpdateString, global_string, zend_grpc_globals,
+                     grpc_globals)
+   PHP_INI_END()
 */
 /* }}} */
 
 /* {{{ php_grpc_init_globals
  */
 /* Uncomment this function if you have INI entries
-static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
-{
-    grpc_globals->global_value = 0;
-    grpc_globals->global_string = NULL;
-}
+   static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
+   {
+     grpc_globals->global_value = 0;
+     grpc_globals->global_string = NULL;
+   }
 */
 /* }}} */
 
@@ -106,7 +111,7 @@ static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
  */
 PHP_MINIT_FUNCTION(grpc) {
   /* If you have INI entries, uncomment these lines
-  REGISTER_INI_ENTRIES();
+     REGISTER_INI_ENTRIES();
   */
   /* Register call error constants */
   grpc_init();
@@ -246,7 +251,7 @@ PHP_MINIT_FUNCTION(grpc) {
  */
 PHP_MSHUTDOWN_FUNCTION(grpc) {
   /* uncomment this line if you have INI entries
-  UNREGISTER_INI_ENTRIES();
+     UNREGISTER_INI_ENTRIES();
   */
   // WARNING: This function IS being called by PHP when the extension
   // is unloaded but the logs were somehow suppressed.
@@ -265,7 +270,7 @@ PHP_MINFO_FUNCTION(grpc) {
   php_info_print_table_end();
 
   /* Remove comments if you have entries in php.ini
-  DISPLAY_INI_ENTRIES();
+     DISPLAY_INI_ENTRIES();
   */
 }
 /* }}} */
@@ -274,12 +279,3 @@ PHP_MINFO_FUNCTION(grpc) {
    function definition, where the functions purpose is also documented. Please
    follow this convention for the convenience of others editing your code.
 */
-
-/*
- * 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
- */
diff --git a/src/php/ext/grpc/php_grpc.h b/src/php/ext/grpc/php_grpc.h
index 1d4834c50f..bd7ee75a6f 100644
--- a/src/php/ext/grpc/php_grpc.h
+++ b/src/php/ext/grpc/php_grpc.h
@@ -72,8 +72,8 @@ PHP_MSHUTDOWN_FUNCTION(grpc);
 PHP_MINFO_FUNCTION(grpc);
 
 /*
-        Declare any global variables you may need between the BEGIN
-        and END macros here:
+  Declare any global variables you may need between the BEGIN
+  and END macros here:
 
 ZEND_BEGIN_MODULE_GLOBALS(grpc)
 ZEND_END_MODULE_GLOBALS(grpc)
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index c13e7cd1f9..50fb2d0cf9 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -58,6 +58,8 @@
 
 zend_class_entry *grpc_ce_server;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instance of wrapped_grpc_server */
 void free_wrapped_grpc_server(void *object TSRMLS_DC) {
   wrapped_grpc_server *server = (wrapped_grpc_server *)object;
@@ -68,6 +70,7 @@ void free_wrapped_grpc_server(void *object TSRMLS_DC) {
                                 gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
     grpc_server_destroy(server->wrapped);
   }
+  zend_object_std_dtor(&server->std TSRMLS_CC);
   efree(server);
 }
 
@@ -90,15 +93,51 @@ zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
   return retval;
 }
 
+#else
+
+static zend_object_handlers server_ce_handlers;
+
+/* Frees and destroys an instance of wrapped_grpc_server */
+static void free_wrapped_grpc_server(zend_object *object) {
+  wrapped_grpc_server *server = wrapped_grpc_server_from_obj(object);
+  if (server->wrapped != NULL) {
+    grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
+    grpc_server_cancel_all_calls(server->wrapped);
+    grpc_completion_queue_pluck(completion_queue, NULL,
+                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+    grpc_server_destroy(server->wrapped);
+  }
+  zend_object_std_dtor(&server->std);
+}
+
+/* Initializes an instance of wrapped_grpc_call to be associated with an object
+ * of a class specified by class_type */
+zend_object *create_wrapped_grpc_server(zend_class_entry *class_type) {
+  wrapped_grpc_server *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_server) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &server_ce_handlers;
+  return &intern->std;
+}
+
+#endif
+
 /**
  * Constructs a new instance of the Server class
  * @param array $args The arguments to pass to the server (optional)
  */
 PHP_METHOD(Server, __construct) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_server *server =
       (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
+#endif
   zval *args_array = NULL;
   grpc_channel_args args;
+
   /* "|a" == 1 optional array */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &args_array) ==
       FAILURE) {
@@ -110,6 +149,8 @@ PHP_METHOD(Server, __construct) {
   if (args_array == NULL) {
     server->wrapped = grpc_server_create(NULL, NULL);
   } else {
+    //TODO(thinkerou): deal it if key of array is long, crash now on php7
+    // and update unit test case
     php_grpc_read_args_array(args_array, &args TSRMLS_CC);
     server->wrapped = grpc_server_create(&args, NULL);
     efree(args.args);
@@ -126,15 +167,22 @@ PHP_METHOD(Server, __construct) {
  */
 PHP_METHOD(Server, requestCall) {
   grpc_call_error error_code;
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
   grpc_call *call;
   grpc_call_details details;
   grpc_metadata_array metadata;
-  zval *result;
   grpc_event event;
+
+#if PHP_MAJOR_VERSION < 7
+  wrapped_grpc_server *server =
+      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  zval *result;
   MAKE_STD_ZVAL(result);
   object_init(result);
+#else
+  wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
+  object_init(return_value);
+#endif
+
   grpc_call_details_init(&details);
   grpc_metadata_array_init(&metadata);
   error_code =
@@ -146,23 +194,48 @@ PHP_METHOD(Server, requestCall) {
     goto cleanup;
   }
   event = grpc_completion_queue_pluck(completion_queue, NULL,
-                                      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+                                      gpr_inf_future(GPR_CLOCK_REALTIME),
+                                      NULL);
   if (!event.success) {
     zend_throw_exception(spl_ce_LogicException,
                          "Failed to request a call for some reason",
                          1 TSRMLS_CC);
     goto cleanup;
   }
+#if PHP_MAJOR_VERSION < 7
   add_property_zval(result, "call", grpc_php_wrap_call(call, true TSRMLS_CC));
   add_property_string(result, "method", details.method, true);
   add_property_string(result, "host", details.host, true);
   add_property_zval(result, "absolute_deadline",
                     grpc_php_wrap_timeval(details.deadline TSRMLS_CC));
-  add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata TSRMLS_CC));
+  add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata
+                                                                  TSRMLS_CC));
+ 
 cleanup:
   grpc_call_details_destroy(&details);
   grpc_metadata_array_destroy(&metadata);
   RETURN_DESTROY_ZVAL(result);
+
+#else
+
+  zval zv_call;
+  zval zv_timeval;
+  zval zv_md;
+  grpc_php_wrap_call(call, true, &zv_call);
+  grpc_php_wrap_timeval(details.deadline, &zv_timeval);
+  grpc_parse_metadata_array(&metadata, &zv_md);
+
+  add_property_zval(return_value, "call", &zv_call);
+  add_property_string(return_value, "method", details.method);
+  add_property_string(return_value, "host", details.host);
+  add_property_zval(return_value, "absolute_deadline", &zv_timeval);
+  add_property_zval(return_value, "metadata", &zv_md);
+
+ cleanup:
+  grpc_call_details_destroy(&details);
+  grpc_metadata_array_destroy(&metadata);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -171,13 +244,19 @@ cleanup:
  * @return true on success, false on failure
  */
 PHP_METHOD(Server, addHttp2Port) {
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
   const char *addr;
+#if PHP_MAJOR_VERSION < 7
   int addr_len;
+  wrapped_grpc_server *server =
+      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  size_t addr_len;
+  wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
+#endif
+
   /* "s" == 1 string */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len) ==
-      FAILURE) {
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len)
+      == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "add_http2_port expects a string", 1 TSRMLS_CC);
     return;
@@ -186,11 +265,17 @@ PHP_METHOD(Server, addHttp2Port) {
 }
 
 PHP_METHOD(Server, addSecureHttp2Port) {
-  wrapped_grpc_server *server =
-      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
   const char *addr;
-  int addr_len;
   zval *creds_obj;
+#if PHP_MAJOR_VERSION < 7
+  int addr_len;
+  wrapped_grpc_server *server =
+      (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  size_t addr_len;
+  wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
+#endif
+
   /* "sO" == 1 string, 1 object */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
                             &creds_obj, grpc_ce_server_credentials) ==
@@ -200,9 +285,14 @@ PHP_METHOD(Server, addSecureHttp2Port) {
         "add_http2_port expects a string and a ServerCredentials", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_server_credentials *creds =
       (wrapped_grpc_server_credentials *)zend_object_store_get_object(
           creds_obj TSRMLS_CC);
+#else
+  wrapped_grpc_server_credentials *creds =
+    Z_WRAPPED_GRPC_SERVER_CREDS_P(creds_obj);
+#endif
   RETURN_LONG(grpc_server_add_secure_http2_port(server->wrapped, addr,
                                                 creds->wrapped));
 }
@@ -212,21 +302,33 @@ PHP_METHOD(Server, addSecureHttp2Port) {
  * @return Void
  */
 PHP_METHOD(Server, start) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_server *server =
       (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  wrapped_grpc_server *server = Z_WRAPPED_GRPC_SERVER_P(getThis());
+#endif
   grpc_server_start(server->wrapped);
 }
 
 static zend_function_entry server_methods[] = {
-    PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Server, requestCall, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+  PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+  PHP_ME(Server, requestCall, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
 
 void grpc_init_server(TSRMLS_D) {
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\Server", server_methods);
   ce.create_object = create_wrapped_grpc_server;
   grpc_ce_server = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&server_ce_handlers, zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  server_ce_handlers.offset = XtOffsetOf(wrapped_grpc_server, std);
+  server_ce_handlers.free_obj = free_wrapped_grpc_server;
+#endif
 }
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index 022257f37c..a7df456a11 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -48,13 +48,33 @@
 /* Class entry for the Server PHP class */
 extern zend_class_entry *grpc_ce_server;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Wrapper struct for grpc_server that can be associated with a PHP object */
 typedef struct wrapped_grpc_server {
   zend_object std;
+  grpc_server *wrapped;
+} wrapped_grpc_server;
 
+#else
+
+/* Wrapper struct for grpc_server that can be associated with a PHP object */
+typedef struct wrapped_grpc_server {
   grpc_server *wrapped;
+  zend_object std;
 } wrapped_grpc_server;
 
+static inline wrapped_grpc_server
+*wrapped_grpc_server_from_obj(zend_object *obj) {
+  return (wrapped_grpc_server*)((char*)(obj) -
+                                XtOffsetOf(wrapped_grpc_server, std));
+}
+
+#define Z_WRAPPED_GRPC_SERVER_P(zv)             \
+  wrapped_grpc_server_from_obj(Z_OBJ_P((zv)))
+
+#endif /* PHP_MAJOR_VERSION */
+
 /* Initializes the Server class */
 void grpc_init_server(TSRMLS_D);
 
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 505da10a28..962b5bc083 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -51,6 +51,8 @@
 
 zend_class_entry *grpc_ce_server_credentials;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instace of wrapped_grpc_server_credentials */
 void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
   wrapped_grpc_server_credentials *creds =
@@ -58,6 +60,7 @@ void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
   if (creds->wrapped != NULL) {
     grpc_server_credentials_release(creds->wrapped);
   }
+  zend_object_std_dtor(&creds->std TSRMLS_CC);
   efree(creds);
 }
 
@@ -92,6 +95,43 @@ zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped TSRMLS_D
   return server_credentials_object;
 }
 
+#else
+
+static zend_object_handlers server_credentials_ce_handlers;
+
+/* Frees and destroys an instace of wrapped_grpc_server_credentials */
+static void free_wrapped_grpc_server_credentials(zend_object *object) {
+  wrapped_grpc_server_credentials *creds =
+    wrapped_grpc_server_creds_from_obj(object);
+  if (creds->wrapped != NULL) {
+    grpc_server_credentials_release(creds->wrapped);
+  }
+  zend_object_std_dtor(&creds->std);
+}
+
+/* Initializes an instace of wrapped_grpc_server_credentials to be associated
+ * with an object of a class specified by class_type */
+zend_object *create_wrapped_grpc_server_credentials(zend_class_entry
+                                                    *class_type) {
+  wrapped_grpc_server_credentials *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_server_credentials) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &server_credentials_ce_handlers;
+  return &intern->std;
+}
+
+void grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped,
+                                      zval *server_credentials_object) {
+  object_init_ex(server_credentials_object, grpc_ce_server_credentials);
+  wrapped_grpc_server_credentials *server_credentials =
+    Z_WRAPPED_GRPC_SERVER_CREDS_P(server_credentials_object);
+  server_credentials->wrapped = wrapped;
+}
+
+#endif
+
 /**
  * Create SSL credentials.
  * @param string pem_root_certs PEM encoding of the server root certificates
@@ -103,7 +143,11 @@ PHP_METHOD(ServerCredentials, createSsl) {
   char *pem_root_certs = 0;
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
 
+#if PHP_MAJOR_VERSION < 7
   int root_certs_length = 0, private_key_length, cert_chain_length;
+#else
+  size_t root_certs_length = 0, private_key_length, cert_chain_length;
+#endif
 
   /* "s!ss" == 1 nullable string, 2 strings */
   /* TODO: support multiple key cert pairs. */
@@ -120,17 +164,33 @@ PHP_METHOD(ServerCredentials, createSsl) {
   grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex(
       pem_root_certs, &pem_key_cert_pair, 1,
       GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, NULL);
+#if PHP_MAJOR_VERSION < 7
   zval *creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
+#else
+  grpc_php_wrap_server_credentials(creds, return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 static zend_function_entry server_credentials_methods[] = {
-    PHP_ME(ServerCredentials, createSsl, NULL,
-           ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
+  PHP_ME(ServerCredentials, createSsl, NULL,
+         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+   PHP_FE_END
+ };
 
 void grpc_init_server_credentials(TSRMLS_D) {
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\ServerCredentials", server_credentials_methods);
   ce.create_object = create_wrapped_grpc_server_credentials;
   grpc_ce_server_credentials = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&server_credentials_ce_handlers,
+         zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  server_credentials_ce_handlers.offset =
+    XtOffsetOf(wrapped_grpc_server_credentials, std);
+  server_credentials_ce_handlers.free_obj =
+    free_wrapped_grpc_server_credentials;
+#endif
 }
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index 7101d65000..d37fafc0dc 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -49,14 +49,34 @@
 /* Class entry for the Server_Credentials PHP class */
 extern zend_class_entry *grpc_ce_server_credentials;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Wrapper struct for grpc_server_credentials that can be associated with a PHP
  * object */
 typedef struct wrapped_grpc_server_credentials {
   zend_object std;
+  grpc_server_credentials *wrapped;
+} wrapped_grpc_server_credentials;
 
+#else
+
+typedef struct wrapped_grpc_server_credentials {
   grpc_server_credentials *wrapped;
+  zend_object std;
 } wrapped_grpc_server_credentials;
 
+static inline wrapped_grpc_server_credentials
+*wrapped_grpc_server_creds_from_obj(zend_object *obj) {
+  return (wrapped_grpc_server_credentials*)
+    ((char*)(obj) -
+     XtOffsetOf(wrapped_grpc_server_credentials, std));
+}
+
+#define Z_WRAPPED_GRPC_SERVER_CREDS_P(zv)           \
+  wrapped_grpc_server_creds_from_obj(Z_OBJ_P((zv)))
+
+#endif /* PHP_MAJOR_VERSION */
+
 /* Initializes the Server_Credentials PHP class */
 void grpc_init_server_credentials(TSRMLS_D);
 
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 5e242162a8..b54b003535 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -52,8 +52,14 @@
 
 zend_class_entry *grpc_ce_timeval;
 
+#if PHP_MAJOR_VERSION < 7
+
 /* Frees and destroys an instance of wrapped_grpc_call */
-void free_wrapped_grpc_timeval(void *object TSRMLS_DC) { efree(object); }
+void free_wrapped_grpc_timeval(void *object TSRMLS_DC) {
+    wrapped_grpc_timeval *timeval = (wrapped_grpc_timeval *)object;
+    zend_object_std_dtor(&timeval->std TSRMLS_CC);
+    efree(timeval);
+}
 
 /* Initializes an instance of wrapped_grpc_timeval to be associated with an
  * object of a class specified by class_type */
@@ -83,14 +89,50 @@ zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC) {
   return timeval_object;
 }
 
+#else
+
+static zend_object_handlers timeval_ce_handlers;
+
+/* Frees and destroys an instance of wrapped_grpc_call */
+static void free_wrapped_grpc_timeval(zend_object *object) {
+  wrapped_grpc_timeval *timeval = wrapped_grpc_timeval_from_obj(object);
+  zend_object_std_dtor(&timeval->std);
+}
+
+/* Initializes an instance of wrapped_grpc_timeval to be associated with an
+ * object of a class specified by class_type */
+zend_object *create_wrapped_grpc_timeval(zend_class_entry *class_type) {
+  wrapped_grpc_timeval *intern;
+  intern = ecalloc(1, sizeof(wrapped_grpc_timeval) +
+                   zend_object_properties_size(class_type));
+  zend_object_std_init(&intern->std, class_type);
+  object_properties_init(&intern->std, class_type);
+  intern->std.handlers = &timeval_ce_handlers;
+  return &intern->std;
+}
+
+void grpc_php_wrap_timeval(gpr_timespec wrapped, zval *timeval_object) {
+  object_init_ex(timeval_object, grpc_ce_timeval);
+  wrapped_grpc_timeval *timeval = Z_WRAPPED_GRPC_TIMEVAL_P(timeval_object);
+  memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec));
+}
+
+#endif
+
 /**
  * Constructs a new instance of the Timeval class
  * @param long $usec The number of microseconds in the interval
  */
 PHP_METHOD(Timeval, __construct) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *timeval =
       (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
   long microseconds;
+#else
+  wrapped_grpc_timeval *timeval = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
+  zend_long microseconds;
+#endif
+
   /* "l" == 1 long */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &microseconds) ==
       FAILURE) {
@@ -110,6 +152,7 @@ PHP_METHOD(Timeval, __construct) {
  */
 PHP_METHOD(Timeval, add) {
   zval *other_obj;
+
   /* "O" == 1 Object */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
                             grpc_ce_timeval) == FAILURE) {
@@ -117,6 +160,7 @@ PHP_METHOD(Timeval, add) {
                          "add expects a Timeval", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *self =
       (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
   wrapped_grpc_timeval *other =
@@ -124,6 +168,14 @@ PHP_METHOD(Timeval, add) {
   zval *sum =
       grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(sum);
+#else
+  wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
+  wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
+
+  grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped),
+                        return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -134,6 +186,7 @@ PHP_METHOD(Timeval, add) {
  */
 PHP_METHOD(Timeval, subtract) {
   zval *other_obj;
+
   /* "O" == 1 Object */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
                             grpc_ce_timeval) == FAILURE) {
@@ -141,6 +194,7 @@ PHP_METHOD(Timeval, subtract) {
                          "subtract expects a Timeval", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *self =
       (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
   wrapped_grpc_timeval *other =
@@ -148,6 +202,13 @@ PHP_METHOD(Timeval, subtract) {
   zval *diff =
       grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(diff);
+#else
+  wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
+  wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
+  grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped),
+                        return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -158,7 +219,9 @@ PHP_METHOD(Timeval, subtract) {
  * @return long
  */
 PHP_METHOD(Timeval, compare) {
-  zval *a_obj, *b_obj;
+  zval *a_obj;
+  zval *b_obj;
+
   /* "OO" == 2 Objects */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &a_obj,
                             grpc_ce_timeval, &b_obj,
@@ -167,10 +230,15 @@ PHP_METHOD(Timeval, compare) {
                          "compare expects two Timevals", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *a =
       (wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
   wrapped_grpc_timeval *b =
       (wrapped_grpc_timeval *)zend_object_store_get_object(b_obj TSRMLS_CC);
+#else
+  wrapped_grpc_timeval *a = Z_WRAPPED_GRPC_TIMEVAL_P(a_obj);
+  wrapped_grpc_timeval *b = Z_WRAPPED_GRPC_TIMEVAL_P(b_obj);
+#endif
   long result = gpr_time_cmp(a->wrapped, b->wrapped);
   RETURN_LONG(result);
 }
@@ -183,7 +251,10 @@ PHP_METHOD(Timeval, compare) {
  * @return bool True if $a and $b are within $threshold, False otherwise
  */
 PHP_METHOD(Timeval, similar) {
-  zval *a_obj, *b_obj, *thresh_obj;
+  zval *a_obj;
+  zval *b_obj;
+  zval *thresh_obj;
+
   /* "OOO" == 3 Objects */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OOO", &a_obj,
                             grpc_ce_timeval, &b_obj, grpc_ce_timeval,
@@ -192,6 +263,7 @@ PHP_METHOD(Timeval, similar) {
                          "compare expects three Timevals", 1 TSRMLS_CC);
     return;
   }
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *a =
       (wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
   wrapped_grpc_timeval *b =
@@ -199,6 +271,11 @@ PHP_METHOD(Timeval, similar) {
   wrapped_grpc_timeval *thresh =
       (wrapped_grpc_timeval *)zend_object_store_get_object(
           thresh_obj TSRMLS_CC);
+#else
+  wrapped_grpc_timeval *a = Z_WRAPPED_GRPC_TIMEVAL_P(a_obj);
+  wrapped_grpc_timeval *b = Z_WRAPPED_GRPC_TIMEVAL_P(b_obj);
+  wrapped_grpc_timeval *thresh = Z_WRAPPED_GRPC_TIMEVAL_P(thresh_obj);
+#endif
   int result = gpr_time_similar(a->wrapped, b->wrapped, thresh->wrapped);
   RETURN_BOOL(result);
 }
@@ -208,8 +285,13 @@ PHP_METHOD(Timeval, similar) {
  * @return Timeval The current time
  */
 PHP_METHOD(Timeval, now) {
+#if PHP_MAJOR_VERSION < 7
   zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(now);
+#else
+  grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME), return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -217,11 +299,18 @@ PHP_METHOD(Timeval, now) {
  * @return Timeval Zero length time interval
  */
 PHP_METHOD(Timeval, zero) {
+#if PHP_MAJOR_VERSION < 7
   zval *grpc_php_timeval_zero =
       grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_ZVAL(grpc_php_timeval_zero,
               false, /* Copy original before returning? */
               true /* Destroy original before returning */);
+#else
+  grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME), return_value);
+  RETURN_ZVAL(return_value,
+              false, /* Copy original before returning? */
+              true /* Destroy original before returning */);
+#endif
 }
 
 /**
@@ -229,9 +318,14 @@ PHP_METHOD(Timeval, zero) {
  * @return Timeval Infinite future time value
  */
 PHP_METHOD(Timeval, infFuture) {
+#if PHP_MAJOR_VERSION < 7
   zval *grpc_php_timeval_inf_future =
       grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
+#else
+  grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME), return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -239,9 +333,14 @@ PHP_METHOD(Timeval, infFuture) {
  * @return Timeval Infinite past time value
  */
 PHP_METHOD(Timeval, infPast) {
+#if PHP_MAJOR_VERSION < 7
   zval *grpc_php_timeval_inf_past =
       grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
+#else
+  grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME), return_value);
+  RETURN_DESTROY_ZVAL(return_value);
+#endif
 }
 
 /**
@@ -249,28 +348,41 @@ PHP_METHOD(Timeval, infPast) {
  * @return void
  */
 PHP_METHOD(Timeval, sleepUntil) {
+#if PHP_MAJOR_VERSION < 7
   wrapped_grpc_timeval *this =
       (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
+#else
+  wrapped_grpc_timeval *this = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
+#endif
   gpr_sleep_until(this->wrapped);
 }
 
 static zend_function_entry timeval_methods[] = {
-    PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, infFuture, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, infPast, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, sleepUntil, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
+  PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+  PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(Timeval, infFuture, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(Timeval, infPast, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(Timeval, sleepUntil, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_FE_END
+};
 
 void grpc_init_timeval(TSRMLS_D) {
   zend_class_entry ce;
   INIT_CLASS_ENTRY(ce, "Grpc\\Timeval", timeval_methods);
   ce.create_object = create_wrapped_grpc_timeval;
   grpc_ce_timeval = zend_register_internal_class(&ce TSRMLS_CC);
+#if PHP_MAJOR_VERSION >= 7
+  memcpy(&timeval_ce_handlers, zend_get_std_object_handlers(),
+         sizeof(zend_object_handlers));
+  timeval_ce_handlers.offset =
+    XtOffsetOf(wrapped_grpc_timeval, std);
+  timeval_ce_handlers.free_obj = free_wrapped_grpc_timeval;
+#endif
 }
 
 void grpc_shutdown_timeval(TSRMLS_D) {}
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
index 7456eb6d58..d4eb2facde 100755
--- a/src/php/ext/grpc/timeval.h
+++ b/src/php/ext/grpc/timeval.h
@@ -50,12 +50,31 @@
 extern zend_class_entry *grpc_ce_timeval;
 
 /* Wrapper struct for timeval that can be associated with a PHP object */
+#if PHP_MAJOR_VERSION < 7
+
 typedef struct wrapped_grpc_timeval {
   zend_object std;
+  gpr_timespec wrapped;
+} wrapped_grpc_timeval;
 
+#else
+
+typedef struct wrapped_grpc_timeval {
   gpr_timespec wrapped;
+  zend_object std;
 } wrapped_grpc_timeval;
 
+static inline wrapped_grpc_timeval
+*wrapped_grpc_timeval_from_obj(zend_object *obj) {
+  return (wrapped_grpc_timeval*)((char*)(obj) -
+                                 XtOffsetOf(wrapped_grpc_timeval, std));
+}
+
+#define Z_WRAPPED_GRPC_TIMEVAL_P(zv)            \
+  wrapped_grpc_timeval_from_obj(Z_OBJ_P((zv)))
+
+#endif /* PHP_MAJOR_VERSION */
+
 /* Initialize the Timeval PHP class */
 void grpc_init_timeval(TSRMLS_D);
 
@@ -63,6 +82,10 @@ void grpc_init_timeval(TSRMLS_D);
 void grpc_shutdown_timeval(TSRMLS_D);
 
 /* Creates a Timeval object that wraps the given timeval struct */
+#if PHP_MAJOR_VERSION < 7
 zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC);
+#else
+void grpc_php_wrap_timeval(gpr_timespec wrapped, zval *timeval_object);
+#endif /* PHP_MAJOR_VERSION */
 
 #endif /* NET_GRPC_PHP_GRPC_TIMEVAL_H_ */
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
old mode 100755
new mode 100644
index df3fe85d44..2fec1bd9cc
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -84,8 +84,8 @@ class BaseStub
         }
         if ($channel) {
             if (!is_a($channel, 'Channel')) {
-                throw new \Exception("The channel argument is not a".
-                                     "Channel object");
+                throw new \Exception('The channel argument is not a'.
+                                     'Channel object');
             }
             $this->channel = $channel;
         } else {
diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index 95e51c5088..c2fdb94b86 100644
--- a/src/php/lib/Grpc/BidiStreamingCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -113,6 +113,7 @@ class BidiStreamingCall extends AbstractCall
         ]);
 
         $this->trailing_metadata = $status_event->status->metadata;
+
         return $status_event->status;
     }
 }
diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index 315a406735..4050f7ed06 100644
--- a/src/php/lib/Grpc/ClientStreamingCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -88,6 +88,7 @@ class ClientStreamingCall extends AbstractCall
 
         $status = $event->status;
         $this->trailing_metadata = $status->metadata;
+
         return [$this->deserializeResponse($event->message), $status];
     }
 }
diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index 53599fe4ae..ba89d9f972 100644
--- a/src/php/lib/Grpc/ServerStreamingCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -92,6 +92,7 @@ class ServerStreamingCall extends AbstractCall
         ]);
 
         $this->trailing_metadata = $status_event->status->metadata;
+
         return $status_event->status;
     }
 }
diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php
index b114b771b8..a71b05dc93 100644
--- a/src/php/lib/Grpc/UnaryCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -77,6 +77,7 @@ class UnaryCall extends AbstractCall
 
         $status = $event->status;
         $this->trailing_metadata = $status->metadata;
+
         return [$this->deserializeResponse($event->message), $status];
     }
 }
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
old mode 100755
new mode 100644
index fa026f0935..087d295ee0
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -50,6 +50,18 @@ class CallTest extends PHPUnit_Framework_TestCase
                                     Grpc\Timeval::infFuture());
     }
 
+    public function tearDown()
+    {
+        unset($this->call);
+        unset($this->channel);
+    }
+
+    public function testConstructor()
+    {
+        $this->assertSame('Grpc\Call', get_class($this->call));
+        $this->assertObjectHasAttribute('channel', $this->call);
+    }
+
     public function testAddEmptyMetadata()
     {
         $batch = [
@@ -89,6 +101,7 @@ class CallTest extends PHPUnit_Framework_TestCase
 
     public function testGetPeer()
     {
+        $this->assertStringStartsWith('localhost:', $this->call->getPeer());
         $this->assertTrue(is_string($this->call->getPeer()));
     }
 
@@ -118,4 +131,38 @@ class CallTest extends PHPUnit_Framework_TestCase
         ];
         $result = $this->call->startBatch($batch);
     }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidConstuctor()
+    {
+        $this->call = new Grpc\Call();
+        $this->assertNull($this->call);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidConstuctor2()
+    {
+        $this->call = new Grpc\Call('hi', 'hi', 'hi');
+        $this->assertNull($this->call);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidSetCredentials()
+    {
+        $this->call->setCredentials('hi');
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidSetCredentials2()
+    {
+        $this->call->setCredentials([]);
+    }
 }
diff --git a/src/php/tests/unit_tests/ChannelCredentialsTest.php b/src/php/tests/unit_tests/ChannelCredentialsTest.php
index 56c1d8f006..11779efaa1 100644
--- a/src/php/tests/unit_tests/ChannelCredentialsTest.php
+++ b/src/php/tests/unit_tests/ChannelCredentialsTest.php
@@ -42,10 +42,22 @@ class ChanellCredentialsTest extends PHPUnit_Framework_TestCase
     {
     }
 
-    public function testCreateDefault()
+    public function testCreateSslWith3Null()
     {
-        $channel_credentials = Grpc\ChannelCredentials::createDefault();
-        $this->assertSame('Grpc\ChannelCredentials', get_class($channel_credentials));
+        $channel_credentials = Grpc\ChannelCredentials::createSsl(null, null, null);
+        $this->assertNotNull($channel_credentials);
+    }
+
+    public function testCreateSslWith3NullString()
+    {
+        $channel_credentials = Grpc\ChannelCredentials::createSsl('', '', '');
+        $this->assertNotNull($channel_credentials);
+    }
+
+    public function testCreateInsecure()
+    {
+        $channel_credentials = Grpc\ChannelCredentials::createInsecure();
+        $this->assertNull($channel_credentials);
     }
 
     /**
@@ -64,10 +76,4 @@ class ChanellCredentialsTest extends PHPUnit_Framework_TestCase
         $channel_credentials = Grpc\ChannelCredentials::createComposite(
             'something', 'something');
     }
-
-    public function testCreateInsecure()
-    {
-        $channel_credentials = Grpc\ChannelCredentials::createInsecure();
-        $this->assertNull($channel_credentials);
-    }
 }
diff --git a/src/php/tests/unit_tests/ChannelTest.php b/src/php/tests/unit_tests/ChannelTest.php
index a1f9053c39..bf8540a44d 100644
--- a/src/php/tests/unit_tests/ChannelTest.php
+++ b/src/php/tests/unit_tests/ChannelTest.php
@@ -40,6 +40,7 @@ class ChannelTest extends PHPUnit_Framework_TestCase
 
     public function tearDown()
     {
+        unset($this->channel);
     }
 
     public function testInsecureCredentials()
@@ -53,6 +54,82 @@ class ChannelTest extends PHPUnit_Framework_TestCase
         $this->assertSame('Grpc\Channel', get_class($this->channel));
     }
 
+    public function testGetConnectivityState()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $state = $this->channel->getConnectivityState();
+        $this->assertEquals(0, $state);
+    }
+
+    public function testGetConnectivityStateWithInt()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $state = $this->channel->getConnectivityState(123);
+        $this->assertEquals(0, $state);
+    }
+
+    public function testGetConnectivityStateWithString()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $state = $this->channel->getConnectivityState('hello');
+        $this->assertEquals(0, $state);
+    }
+
+    public function testGetConnectivityStateWithBool()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $state = $this->channel->getConnectivityState(true);
+        $this->assertEquals(0, $state);
+    }
+
+    public function testGetTarget()
+    {
+        $this->channel = new Grpc\Channel('localhost:8888',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $target = $this->channel->getTarget();
+        $this->assertSame('localhost:8888', $target);
+    }
+
+    public function testWatchConnectivityState()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $time = new Grpc\Timeval(1000);
+        $state = $this->channel->watchConnectivityState(123, $time);
+        $this->assertTrue($state);
+        unset($time);
+    }
+
+    public function testClose()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $this->assertNotNull($this->channel);
+        $this->channel->close();
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidConstructorWithNull()
+    {
+        $this->channel = new Grpc\Channel();
+        $this->assertNull($this->channel);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidConstructorWith()
+    {
+        $this->channel = new Grpc\Channel('localhost', 'invalid');
+        $this->assertNull($this->channel);
+    }
+
     /**
      * @expectedException InvalidArgumentException
      */
@@ -78,4 +155,34 @@ class ChannelTest extends PHPUnit_Framework_TestCase
             ]
         );
     }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidGetConnectivityStateWithArray()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+            ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $this->channel->getConnectivityState([]);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidWatchConnectivityState()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+            ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $this->channel->watchConnectivityState([]);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidWatchConnectivityState2()
+    {
+        $this->channel = new Grpc\Channel('localhost:0',
+            ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+        $this->channel->watchConnectivityState(1, 'hi');
+    }
 }
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
old mode 100755
new mode 100644
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
old mode 100755
new mode 100644
diff --git a/src/php/tests/unit_tests/ServerTest.php b/src/php/tests/unit_tests/ServerTest.php
index 76aaa06970..6dd607a533 100644
--- a/src/php/tests/unit_tests/ServerTest.php
+++ b/src/php/tests/unit_tests/ServerTest.php
@@ -36,27 +36,145 @@ class ServerTest extends PHPUnit_Framework_TestCase
 {
     public function setUp()
     {
+        $this->server = null;
     }
 
     public function tearDown()
     {
+        unset($this->server);
     }
 
+    public function testConstructorWithNull()
+    {
+        $this->server = new Grpc\Server();
+        $this->assertNotNull($this->server);
+    }
+
+    public function testConstructorWithNullArray()
+    {
+        $this->server = new Grpc\Server([]);
+        $this->assertNotNull($this->server);
+    }
+
+    public function testConstructorWithArray()
+    {
+        // key of array must be string
+         $this->server = new Grpc\Server(['ip' => '127.0.0.1',
+                                          'port' => '8080', ]);
+        $this->assertNotNull($this->server);
+    }
+
+    public function testRequestCall()
+    {
+        $this->server = new Grpc\Server();
+        $port = $this->server->addHttp2Port('0.0.0.0:8888');
+        $this->server->start();
+        $channel = new Grpc\Channel('localhost:8888',
+             ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
+
+        $deadline = Grpc\Timeval::infFuture();
+        $call = new Grpc\Call($channel, 'dummy_method', $deadline);
+
+        $event = $call->startBatch([Grpc\OP_SEND_INITIAL_METADATA => [],
+                                     Grpc\OP_SEND_CLOSE_FROM_CLIENT => true, ]);
+
+        $c = $this->server->requestCall();
+        $this->assertObjectHasAttribute('call', $c);
+        $this->assertObjectHasAttribute('method', $c);
+        $this->assertSame('dummy_method', $c->method);
+        $this->assertObjectHasAttribute('host', $c);
+        $this->assertSame('localhost:8888', $c->host);
+        $this->assertObjectHasAttribute('absolute_deadline', $c);
+        $this->assertObjectHasAttribute('metadata', $c);
+
+        unset($call);
+        unset($channel);
+    }
+
+    private function createSslObj()
+    {
+        $server_credentials = Grpc\ServerCredentials::createSsl(
+             null,
+             file_get_contents(dirname(__FILE__).'/../data/server1.key'),
+             file_get_contents(dirname(__FILE__).'/../data/server1.pem'));
+
+        return $server_credentials;
+    }
+/*
+    //TODO(thinkerou): make cases of addHttp2Port right
+    public function testAddHttp2Port()
+    {
+        $this->server = new Grpc\Server();
+        $port = $this->server->addHttp2Port('127.0.0.1:8080');
+        $this->assertEquals(8080, $port);
+    }
+
+    public function testAddHttp2Port1()
+    {
+        $this->server = new Grpc\Server([]);
+        $port = $this->server->addHttp2Port('127.0.0.1:8080');
+        $this->assertEquals(8080, $port);
+    }
+
+    public function testAddHttp2Port2()
+    {
+        $this->server = new Grpc\Server(['ip' => '127.0.0.1',
+                                          'port' => '8888', ]);
+        $port = $this->server->addHttp2Port('127.0.0.1:8080');
+        $this->assertEquals(8080, $port);
+    }
+
+    public function testAddSecureHttp2Port()
+    {
+        $this->server = new Grpc\Server();
+        $cred = $this->createSslObj();
+        $port = $this->server->addSecureHttp2Port('127.0.0.1:8080', $cred);
+        $this->assertEquals(8080, $port);
+    }
+
+    public function testAddSecureHttp2Port1()
+    {
+        $this->server = new Grpc\Server([]);
+        $cred = $this->createSslObj();
+        $port = $this->server->addSecureHttp2Port('127.0.0.1:8080', $cred);
+        $this->assertEquals(8080, $port);
+    }
+
+    public function testAddSecureHttp2Port2()
+    {
+        $this->server = new Grpc\Server(['ip' => '127.0.0.1',
+                                         'port' => '8888', ]);
+        $cred = $this->createSslObj();
+        $port = $this->server->addSecureHttp2Port('127.0.0.1:8080', $cred);
+        $this->assertEquals(8080, $port);
+    }
+*/
     /**
      * @expectedException InvalidArgumentException
      */
     public function testInvalidConstructor()
     {
-        $server = new Grpc\Server('invalid_host');
+        $this->server = new Grpc\Server('invalid_host');
+        $this->assertNull($this->server);
     }
 
+    /**
+     * @expectedException InvalidArgumentException
+     */
+/*    public function testInvalidConstructor2()
+    {
+        //TODO(thinkerou): it crash when key is long on php7
+        $this->server = new Grpc\server(['0.0.0.0:0']);
+        $this->assertNull($this->server);
+    }
+*/
     /**
      * @expectedException InvalidArgumentException
      */
     public function testInvalidAddHttp2Port()
     {
         $this->server = new Grpc\Server([]);
-        $this->port = $this->server->addHttp2Port(['0.0.0.0:0']);
+        $port = $this->server->addHttp2Port(['0.0.0.0:0']);
     }
 
     /**
@@ -65,6 +183,24 @@ class ServerTest extends PHPUnit_Framework_TestCase
     public function testInvalidAddSecureHttp2Port()
     {
         $this->server = new Grpc\Server([]);
-        $this->port = $this->server->addSecureHttp2Port(['0.0.0.0:0']);
+        $port = $this->server->addSecureHttp2Port(['0.0.0.0:0']);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidAddSecureHttp2Port2()
+    {
+        $this->server = new Grpc\Server();
+        $port = $this->server->addSecureHttp2Port('0.0.0.0:0');
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidAddSecureHttp2Port3()
+    {
+        $this->server = new Grpc\Server();
+        $port = $this->server->addSecureHttp2Port('0.0.0.0:0', 'invalid');
     }
 }
diff --git a/src/php/tests/unit_tests/TimevalTest.php b/src/php/tests/unit_tests/TimevalTest.php
old mode 100755
new mode 100644
index a3dbce079f..2d19f64c79
--- a/src/php/tests/unit_tests/TimevalTest.php
+++ b/src/php/tests/unit_tests/TimevalTest.php
@@ -33,6 +33,57 @@
  */
 class TimevalTest extends PHPUnit_Framework_TestCase
 {
+    public function setUp()
+    {
+    }
+
+    public function tearDown()
+    {
+        unset($this->time);
+    }
+
+    public function testConstructorWithInt()
+    {
+        $this->time = new Grpc\Timeval(1234);
+        $this->assertNotNull($this->time);
+        $this->assertSame('Grpc\Timeval', get_class($this->time));
+    }
+
+    public function testConstructorWithNegative()
+    {
+        $this->time = new Grpc\Timeval(-123);
+        $this->assertNotNull($this->time);
+        $this->assertSame('Grpc\Timeval', get_class($this->time));
+    }
+
+    public function testConstructorWithZero()
+    {
+        $this->time = new Grpc\Timeval(0);
+        $this->assertNotNull($this->time);
+        $this->assertSame('Grpc\Timeval', get_class($this->time));
+    }
+
+    public function testConstructorWithOct()
+    {
+        $this->time = new Grpc\Timeval(0123);
+        $this->assertNotNull($this->time);
+        $this->assertSame('Grpc\Timeval', get_class($this->time));
+    }
+
+    public function testConstructorWithHex()
+    {
+        $this->time = new Grpc\Timeval(0x1A);
+        $this->assertNotNull($this->time);
+        $this->assertSame('Grpc\Timeval', get_class($this->time));
+    }
+
+    public function testConstructorWithFloat()
+    {
+        $this->time = new Grpc\Timeval(123.456);
+        $this->assertNotNull($this->time);
+        $this->assertSame('Grpc\Timeval', get_class($this->time));
+    }
+
     public function testCompareSame()
     {
         $zero = Grpc\Timeval::zero();
@@ -70,6 +121,7 @@ class TimevalTest extends PHPUnit_Framework_TestCase
     public function testNowAndAdd()
     {
         $now = Grpc\Timeval::now();
+        $this->assertNotNull($now);
         $delta = new Grpc\Timeval(1000);
         $deadline = $now->add($delta);
         $this->assertGreaterThan(0, Grpc\Timeval::compare($deadline, $now));
@@ -154,5 +206,6 @@ class TimevalTest extends PHPUnit_Framework_TestCase
     public function testSimilarInvalidParam()
     {
         $a = Grpc\Timeval::similar(1000, 1100, 1200);
+        $this->assertNull($delta);
     }
 }
-- 
GitLab