Merge pull request #7553 from podsvirov/topic-cmake-template

CMake Project Improvements
diff --git a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
index 86909d8..ff22507 100644
--- a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
+++ b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
@@ -2,9 +2,39 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+	<key>AD_UNIT_ID_FOR_BANNER_TEST</key>
+	<string>redacted</string>
+	<key>AD_UNIT_ID_FOR_INTERSTITIAL_TEST</key>
+	<string>redacted</string>
 	<key>CLIENT_ID</key>
 	<string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string>
 	<key>REVERSED_CLIENT_ID</key>
 	<string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
+	<key>API_KEY</key>
+	<string>redacted</string>
+	<key>GCM_SENDER_ID</key>
+	<string>redacted</string>
+	<key>PLIST_VERSION</key>
+	<string>1</string>
+	<key>BUNDLE_ID</key>
+	<string>io.grpc.AuthSample</string>
+	<key>PROJECT_ID</key>
+	<string>grpc-authsample</string>
+	<key>STORAGE_BUCKET</key>
+	<string>grpc-authsample.appspot.com</string>
+	<key>IS_ADS_ENABLED</key>
+	<false/>
+	<key>IS_ANALYTICS_ENABLED</key>
+	<false/>
+	<key>IS_APPINVITE_ENABLED</key>
+	<false/>
+	<key>IS_GCM_ENABLED</key>
+	<false/>
+	<key>IS_SIGNIN_ENABLED</key>
+	<true/>
+	<key>GOOGLE_APP_ID</key>
+	<string>1:15087385131:ios:d547168abe3c362f</string>
+	<key>DATABASE_URL</key>
+	<string>https://grpc-authsample.firebaseio.com</string>
 </dict>
-</plist>
\ No newline at end of file
+</plist>
diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h
index e96d224..70533aa 100644
--- a/include/grpc++/impl/codegen/async_stream.h
+++ b/include/grpc++/impl/codegen/async_stream.h
@@ -330,6 +330,9 @@
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_ops_);
   }
@@ -345,6 +348,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // The response is dropped if the status is not OK.
@@ -363,6 +369,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@@ -400,6 +409,9 @@
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_ops_);
   }
@@ -409,6 +421,9 @@
     if (!ctx_->sent_initial_metadata_) {
       write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        write_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // TODO(ctiller): don't assert
@@ -421,6 +436,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@@ -459,6 +477,9 @@
     meta_ops_.set_output_tag(tag);
     meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_ops_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_ops_);
   }
@@ -474,6 +495,9 @@
     if (!ctx_->sent_initial_metadata_) {
       write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                      ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        write_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // TODO(ctiller): don't assert
@@ -486,6 +510,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_ops_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index 05681e2..5ceab73 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -126,6 +126,9 @@
     meta_buf_.set_output_tag(tag);
     meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
                                   ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      meta_buf_.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_.PerformOps(&meta_buf_);
   }
@@ -135,6 +138,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_buf_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     // The response is dropped if the status is not OK.
@@ -153,6 +159,9 @@
     if (!ctx_->sent_initial_metadata_) {
       finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
                                       ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        finish_buf_.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index fab85d1..dfac177 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -180,17 +180,23 @@
 
 class CallOpSendInitialMetadata {
  public:
-  CallOpSendInitialMetadata() : send_(false) {}
+  CallOpSendInitialMetadata() : send_(false) {
+    maybe_compression_level_.is_set = false;
+  }
 
   void SendInitialMetadata(
       const std::multimap<grpc::string, grpc::string>& metadata,
       uint32_t flags) {
+    maybe_compression_level_.is_set = false;
     send_ = true;
     flags_ = flags;
     initial_metadata_count_ = metadata.size();
     initial_metadata_ = FillMetadataArray(metadata);
-    // TODO(dgq): expose compression level in API so it can be properly set.
-    maybe_compression_level_.is_set = false;
+  }
+
+  void set_compression_level(grpc_compression_level level) {
+    maybe_compression_level_.is_set = true;
+    maybe_compression_level_.level = level;
   }
 
  protected:
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h
index 21ac6c4..2f4be64 100644
--- a/include/grpc++/impl/codegen/method_handler_impl.h
+++ b/include/grpc++/impl/codegen/method_handler_impl.h
@@ -65,6 +65,9 @@
         ops;
     ops.SendInitialMetadata(param.server_context->initial_metadata_,
                             param.server_context->initial_metadata_flags());
+    if (param.server_context->compression_level_set()) {
+      ops.set_compression_level(param.server_context->compression_level());
+    }
     if (status.ok()) {
       status = ops.SendMessage(rsp);
     }
@@ -104,6 +107,9 @@
         ops;
     ops.SendInitialMetadata(param.server_context->initial_metadata_,
                             param.server_context->initial_metadata_flags());
+    if (param.server_context->compression_level_set()) {
+      ops.set_compression_level(param.server_context->compression_level());
+    }
     if (status.ok()) {
       status = ops.SendMessage(rsp);
     }
@@ -144,6 +150,9 @@
     if (!param.server_context->sent_initial_metadata_) {
       ops.SendInitialMetadata(param.server_context->initial_metadata_,
                               param.server_context->initial_metadata_flags());
+      if (param.server_context->compression_level_set()) {
+        ops.set_compression_level(param.server_context->compression_level());
+      }
     }
     ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
     param.call->PerformOps(&ops);
@@ -177,6 +186,9 @@
     if (!param.server_context->sent_initial_metadata_) {
       ops.SendInitialMetadata(param.server_context->initial_metadata_,
                               param.server_context->initial_metadata_flags());
+      if (param.server_context->compression_level_set()) {
+        ops.set_compression_level(param.server_context->compression_level());
+      }
     }
     ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
     param.call->PerformOps(&ops);
@@ -199,6 +211,9 @@
     if (!context->sent_initial_metadata_) {
       ops->SendInitialMetadata(context->initial_metadata_,
                                context->initial_metadata_flags());
+      if (context->compression_level_set()) {
+        ops->set_compression_level(context->compression_level());
+      }
       context->sent_initial_metadata_ = true;
     }
     ops->ServerSendStatus(context->trailing_metadata_, status);
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index cea13a5..08212af 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -130,7 +130,13 @@
   grpc_compression_level compression_level() const {
     return compression_level_;
   }
-  void set_compression_level(grpc_compression_level level);
+
+  void set_compression_level(grpc_compression_level level) {
+    compression_level_set_ = true;
+    compression_level_ = level;
+  }
+
+  bool compression_level_set() const { return compression_level_set_; }
 
   grpc_compression_algorithm compression_algorithm() const {
     return compression_algorithm_;
@@ -217,6 +223,7 @@
   std::multimap<grpc::string, grpc::string> initial_metadata_;
   std::multimap<grpc::string, grpc::string> trailing_metadata_;
 
+  bool compression_level_set_;
   grpc_compression_level compression_level_;
   grpc_compression_algorithm compression_algorithm_;
 };
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
index cbfa410..b2b9727 100644
--- a/include/grpc++/impl/codegen/sync_stream.h
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -347,6 +347,9 @@
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_,
                             ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_->PerformOps(&ops);
     call_->cq()->Pluck(&ops);
@@ -375,6 +378,9 @@
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_,
                             ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_->PerformOps(&ops);
     call_->cq()->Pluck(&ops);
@@ -389,6 +395,9 @@
     if (!ctx_->sent_initial_metadata_) {
       ops.SendInitialMetadata(ctx_->initial_metadata_,
                               ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ops.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     call_->PerformOps(&ops);
@@ -413,6 +422,9 @@
     CallOpSet<CallOpSendInitialMetadata> ops;
     ops.SendInitialMetadata(ctx_->initial_metadata_,
                             ctx_->initial_metadata_flags());
+    if (ctx_->compression_level_set()) {
+      ops.set_compression_level(ctx_->compression_level());
+    }
     ctx_->sent_initial_metadata_ = true;
     call_->PerformOps(&ops);
     call_->cq()->Pluck(&ops);
@@ -434,6 +446,9 @@
     if (!ctx_->sent_initial_metadata_) {
       ops.SendInitialMetadata(ctx_->initial_metadata_,
                               ctx_->initial_metadata_flags());
+      if (ctx_->compression_level_set()) {
+        ops.set_compression_level(ctx_->compression_level());
+      }
       ctx_->sent_initial_metadata_ = true;
     }
     call_->PerformOps(&ops);
diff --git a/package.xml b/package.xml
index 66bd688..f395334 100644
--- a/package.xml
+++ b/package.xml
@@ -10,7 +10,7 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2016-07-21</date>
+ <date>2016-07-28</date>
  <time>16:06:07</time>
  <version>
   <release>1.1.0</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-- PHP7 Support #7464
+- PHP7 Support continued, reduce code duplication #7543
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -1118,5 +1118,20 @@
 - PHP7 Support #7464
    </notes>
   </release>
+  <release>
+   <version>
+    <release>1.0.0RC3</release>
+    <api>1.0.0RC3</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2016-07-28</date>
+   <license>BSD</license>
+   <notes>
+- PHP7 Support continued, reduce code duplication #7543
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/src/compiler/ruby_generator_helpers-inl.h b/src/compiler/ruby_generator_helpers-inl.h
index ff6939e..aa3c22f 100644
--- a/src/compiler/ruby_generator_helpers-inl.h
+++ b/src/compiler/ruby_generator_helpers-inl.h
@@ -48,7 +48,7 @@
       file->name().find_last_of(".proto") == file->name().size() - 1) {
     *file_name_or_error =
         file->name().substr(0, file->name().size() - proto_suffix_length) +
-        "_services.rb";
+        "_services_pb.rb";
     return true;
   } else {
     *file_name_or_error = "Invalid proto file name:  must end with .proto";
@@ -58,7 +58,7 @@
 
 inline grpc::string MessagesRequireName(
     const grpc::protobuf::FileDescriptor *file) {
-  return Replace(file->name(), ".proto", "");
+  return Replace(file->name(), ".proto", "_pb");
 }
 
 // Get leading or trailing comments in a string. Comment lines start with "# ".
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 43117fd..1ca6a2b 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -129,7 +129,8 @@
       deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
       call_(nullptr),
       cq_(nullptr),
-      sent_initial_metadata_(false) {}
+      sent_initial_metadata_(false),
+      compression_level_set_(false) {}
 
 ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
                              size_t metadata_count)
@@ -139,7 +140,8 @@
       deadline_(deadline),
       call_(nullptr),
       cq_(nullptr),
-      sent_initial_metadata_(false) {
+      sent_initial_metadata_(false),
+      compression_level_set_(false) {
   for (size_t i = 0; i < metadata_count; i++) {
     client_metadata_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
         metadata[i].key,
@@ -194,15 +196,6 @@
   }
 }
 
-void ServerContext::set_compression_level(grpc_compression_level level) {
-  // TODO(dgq): get rid of grpc_call_compression_for_level and propagate the
-  // compression level by adding a new argument to
-  // CallOpSendInitialMetadata::SendInitialMetadata.
-  const grpc_compression_algorithm algorithm_for_level =
-      grpc_call_compression_for_level(call_, level);
-  set_compression_algorithm(algorithm_for_level);
-}
-
 void ServerContext::set_compression_algorithm(
     grpc_compression_algorithm algorithm) {
   char* algorithm_name = NULL;
diff --git a/src/csharp/.nuget/packages.config b/src/csharp/.nuget/packages.config
deleted file mode 100644
index 6154b35..0000000
--- a/src/csharp/.nuget/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="NUnit.ConsoleRunner" version="3.2.0" />
-  <package id="OpenCover" version="4.6.519" />
-  <package id="ReportGenerator" version="2.4.4.0" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 501992c..9d069fa 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -58,10 +58,11 @@
         [Test]
         public void TestsJsonUpToDate()
         {
-            var discoveredTests = DiscoverAllTestClasses();
-            string discoveredTestsJson = JsonConvert.SerializeObject(discoveredTests, Formatting.Indented);
+            Dictionary<string, List<string>> discoveredTests = DiscoverAllTestClasses();
+			Dictionary<string, List<string>> testsFromFile 
+			    = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(ReadTestsJson());
 
-            Assert.AreEqual(discoveredTestsJson, ReadTestsJson());
+            Assert.AreEqual(discoveredTests, testsFromFile);
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index aa7d951..6a930c1 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -4,4 +4,7 @@
   <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
   <package id="NUnit" version="3.2.0" targetFramework="net45" />
   <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
-</packages>
\ No newline at end of file
+  <package id="NUnit.ConsoleRunner" version="3.2.0" />
+  <package id="OpenCover" version="4.6.519" />
+  <package id="ReportGenerator" version="2.4.4.0" />
+</packages>
diff --git a/src/csharp/Grpc.Core.Tests/project.json b/src/csharp/Grpc.Core.Tests/project.json
index d4c9a2e..4a682d9 100644
--- a/src/csharp/Grpc.Core.Tests/project.json
+++ b/src/csharp/Grpc.Core.Tests/project.json
@@ -54,7 +54,10 @@
     },
     "Newtonsoft.Json": "8.0.3",
     "NUnit": "3.2.0",
-    "NUnitLite": "3.2.0-*"
+    "NUnitLite": "3.2.0-*",
+    "NUnit.ConsoleRunner": "3.2.0",
+    "OpenCover": "4.6.519",
+    "ReportGenerator": "2.4.4.0"
   },
   "frameworks": {
     "net45": { },
diff --git a/src/csharp/Grpc.Examples.MathClient/packages.config b/src/csharp/Grpc.Examples.MathClient/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.Examples.MathServer/packages.config b/src/csharp/Grpc.Examples.MathServer/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config b/src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/packages.config b/src/csharp/Grpc.IntegrationTesting.StressClient/packages.config
new file mode 100644
index 0000000..79ece06
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/packages.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+</packages>
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
index 3c8f0c5..81fc552 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -68,6 +68,8 @@
 Nan::Callback *CallCredentials::constructor;
 Persistent<FunctionTemplate> CallCredentials::fun_tpl;
 
+static Callback *plugin_callback;
+
 CallCredentials::CallCredentials(grpc_call_credentials *credentials)
     : wrapped_credentials(credentials) {}
 
@@ -88,6 +90,11 @@
                Nan::New<FunctionTemplate>(CreateFromPlugin)).ToLocalChecked());
   Nan::Set(exports, Nan::New("CallCredentials").ToLocalChecked(), ctr);
   constructor = new Nan::Callback(ctr);
+
+  Local<FunctionTemplate> callback_tpl =
+      Nan::New<FunctionTemplate>(PluginCallback);
+  plugin_callback = new Callback(
+      Nan::GetFunction(callback_tpl).ToLocalChecked());
 }
 
 bool CallCredentials::HasInstance(Local<Value> val) {
@@ -195,23 +202,28 @@
     return Nan::ThrowTypeError(
         "The callback's third argument must be an object");
   }
+  if (!info[3]->IsObject()) {
+    return Nan::ThrowTypeError(
+        "The callback's fourth argument must be an object");
+  }
   shared_ptr<Resources> resources(new Resources);
   grpc_status_code code = static_cast<grpc_status_code>(
       Nan::To<uint32_t>(info[0]).FromJust());
   Utf8String details_utf8_str(info[1]);
   char *details = *details_utf8_str;
   grpc_metadata_array array;
+  Local<Object> callback_data = Nan::To<Object>(info[3]).ToLocalChecked();
   if (!CreateMetadataArray(Nan::To<Object>(info[2]).ToLocalChecked(),
                            &array, resources)){
     return Nan::ThrowError("Failed to parse metadata");
   }
   grpc_credentials_plugin_metadata_cb cb =
       reinterpret_cast<grpc_credentials_plugin_metadata_cb>(
-          Nan::Get(info.Callee(),
+          Nan::Get(callback_data,
                    Nan::New("cb").ToLocalChecked()
                    ).ToLocalChecked().As<External>()->Value());
   void *user_data =
-      Nan::Get(info.Callee(),
+      Nan::Get(callback_data,
                Nan::New("user_data").ToLocalChecked()
                ).ToLocalChecked().As<External>()->Value();
   cb(user_data, array.metadata, array.count, code, details);
@@ -227,17 +239,17 @@
   while (!callbacks.empty()) {
     plugin_callback_data *data = callbacks.front();
     callbacks.pop_front();
-    // Attach cb and user_data to plugin_callback so that it can access them later
-    v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
-        Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked();
-    Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(),
+    Local<Object> callback_data = Nan::New<Object>();
+    Nan::Set(callback_data, Nan::New("cb").ToLocalChecked(),
              Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
-    Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(),
+    Nan::Set(callback_data, Nan::New("user_data").ToLocalChecked(),
              Nan::New<v8::External>(data->user_data));
-    const int argc = 2;
+    const int argc = 3;
     v8::Local<v8::Value> argv[argc] = {
       Nan::New(data->service_url).ToLocalChecked(),
-      plugin_callback
+      callback_data,
+      // Get Local<Function> from Nan::Callback*
+      **plugin_callback
     };
     Nan::Callback *callback = state->callback;
     callback->Call(argc, argv);
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index 67f5301..40e2760 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -19,11 +19,11 @@
     "lodash": "^3.9.3",
     "google-protobuf": "^3.0.0-alpha.5"
   },
-  "files": {
+  "files": [
     "LICENSE",
     "health.js",
     "v1"
-  },
+  ],
   "main": "src/node/index.js",
   "license": "BSD-3-Clause"
 }
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index b746d06..043df06 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -92,7 +92,8 @@
  * @return {CallCredentials} The credentials object
  */
 exports.createFromMetadataGenerator = function(metadata_generator) {
-  return CallCredentials.createFromPlugin(function(service_url, callback) {
+  return CallCredentials.createFromPlugin(function(service_url, cb_data,
+                                                   callback) {
     metadata_generator({service_url: service_url}, function(error, metadata) {
       var code = grpc.status.OK;
       var message = '';
@@ -107,7 +108,7 @@
           metadata = new Metadata();
         }
       }
-      callback(code, message, metadata._getCoreRepresentation());
+      callback(code, message, metadata._getCoreRepresentation(), cb_data);
     });
   });
 };
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index fc832da..66ca151 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -58,65 +58,27 @@
 #include "byte_buffer.h"
 
 zend_class_entry *grpc_ce_call;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers call_ce_handlers;
+#endif
 
 /* 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);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call)
+  if (p->owned && p->wrapped != NULL) {
+    grpc_call_destroy(p->wrapped);
   }
-  zend_object_std_dtor(&call->std TSRMLS_CC);
-  efree(call);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_call to be associated with an object
  * of a class specified by class_type */
-zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type
-                                               TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_call *intern;
-
-  intern = (wrapped_grpc_call *)emalloc(sizeof(wrapped_grpc_call));
-  memset(intern, 0, sizeof(wrapped_grpc_call));
-
+php_grpc_zend_object create_wrapped_grpc_call(zend_class_entry *class_type
+                                              TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_call, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call, call_ce_handlers);
 }
 
-#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;
-}
-
-#endif
-
 /* Creates and returns a PHP array object with the data in a
  * grpc_metadata_array. Returns NULL on failure */
 zval *grpc_parse_metadata_array(grpc_metadata_array
@@ -132,11 +94,7 @@
   char *str_key;
   char *str_val;
   size_t key_len;
-#if PHP_MAJOR_VERSION < 7
-  zval **data = NULL;
-#else
- zval *data;
-#endif
+  zval *data = NULL;
 
   array_hash = Z_ARRVAL_P(array);
   grpc_metadata *elem;
@@ -147,14 +105,9 @@
     memcpy(str_key, elem->key, key_len);
     str_val = ecalloc(elem->value_length + 1, sizeof(char));
     memcpy(str_val, elem->value, elem->value_length);
-#if PHP_MAJOR_VERSION < 7
-    if (zend_hash_find(array_hash, str_key, key_len, (void **)data) ==
-        SUCCESS) {
-      if (Z_TYPE_P(*data) != IS_ARRAY) {
-#else
-    if ((data = zend_hash_str_find(array_hash, str_key, key_len)) != NULL) {
+    if (php_grpc_zend_hash_find(array_hash, str_key, key_len, (void **)&data)
+        == SUCCESS) {
       if (Z_TYPE_P(data) != IS_ARRAY) {
-#endif
         zend_throw_exception(zend_exception_get_default(TSRMLS_C),
                              "Metadata hash somehow contains wrong types.",
                              1 TSRMLS_CC);
@@ -162,13 +115,8 @@
         efree(str_val);
         return NULL;
       }
-#if PHP_MAJOR_VERSION < 7
-      php_grpc_add_next_index_stringl(*data, str_val, elem->value_length,
-                                      false);
-#else
       php_grpc_add_next_index_stringl(data, str_val, elem->value_length,
                                       false);
-#endif
     } else {
       PHP_GRPC_MAKE_STD_ZVAL(inner_array);
       array_init(inner_array);
@@ -185,96 +133,48 @@
 bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
   HashTable *array_hash;
   HashTable *inner_array_hash;
-#if PHP_MAJOR_VERSION < 7
-  zval **inner_array;
-  zval **value;
-  HashPosition array_pointer;
-  HashPosition inner_array_pointer;
-  char *key;
-  uint key_len;
-  ulong index;
-#else
-  zval *inner_array;
   zval *value;
-  zend_string *key;
-#endif
+  zval *inner_array;
   if (Z_TYPE_P(array) != IS_ARRAY) {
     return false;
   }
   grpc_metadata_array_init(metadata);
   array_hash = Z_ARRVAL_P(array);
-#if PHP_MAJOR_VERSION < 7
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
-      return false;
-    }
-    if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
-      return false;
-    }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    metadata->capacity += zend_hash_num_elements(inner_array_hash);
-  }
-#else
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
-    if (key == NULL) {
+
+  char *key;
+  int key_type;
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type,
+                                          inner_array)
+    if (key_type != HASH_KEY_IS_STRING || key == NULL) {
       return false;
     }
     if (Z_TYPE_P(inner_array) != IS_ARRAY) {
       return false;
     }
-    inner_array_hash = HASH_OF(inner_array);
+    inner_array_hash = Z_ARRVAL_P(inner_array);
     metadata->capacity += zend_hash_num_elements(inner_array_hash);
-  } ZEND_HASH_FOREACH_END();
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 
   metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
 
-#if PHP_MAJOR_VERSION < 7
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
+  char *key1 = NULL;
+  int key_type1;
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key1, key_type1,
+                                          inner_array)
+    if (key_type1 != HASH_KEY_IS_STRING) {
       return false;
     }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
-                                             &inner_array_pointer);
-         zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
-                                       &inner_array_pointer) == SUCCESS;
-         zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
-      if (Z_TYPE_P(*value) != IS_STRING) {
-        return false;
-      }
-      metadata->metadata[metadata->count].key = key;
-      metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
-      metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
-      metadata->count += 1;
-    }
-  }
-#else
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, inner_array) {
-    if (key == NULL) {
-      return false;
-    }
-    inner_array_hash = HASH_OF(inner_array);
-
-    ZEND_HASH_FOREACH_VAL(inner_array_hash, value) {
+    inner_array_hash = Z_ARRVAL_P(inner_array);
+    PHP_GRPC_HASH_FOREACH_VAL_START(inner_array_hash, value)
       if (Z_TYPE_P(value) != IS_STRING) {
         return false;
       }
-      metadata->metadata[metadata->count].key = ZSTR_VAL(key);
+      metadata->metadata[metadata->count].key = key1;
       metadata->metadata[metadata->count].value = Z_STRVAL_P(value);
       metadata->metadata[metadata->count].value_length = Z_STRLEN_P(value);
       metadata->count += 1;
-    } ZEND_HASH_FOREACH_END();
-  } ZEND_HASH_FOREACH_END();
-#endif
+    PHP_GRPC_HASH_FOREACH_END()
+  PHP_GRPC_HASH_FOREACH_END()
   return true;
 }
 
@@ -342,23 +242,13 @@
   PHP_GRPC_MAKE_STD_ZVAL(result);
   object_init(result);
   php_grpc_ulong index;
-#if PHP_MAJOR_VERSION < 7
-  zval **value;
-  zval **inner_value;
-  HashPosition array_pointer;
-  zval **message_value;
-  zval **message_flags;
-  char *key;
-  uint key_len;
   zval *recv_status;
-#else
+  PHP_GRPC_MAKE_STD_ZVAL(recv_status);
+  object_init(recv_status);
   zval *value;
   zval *inner_value;
   zval *message_value;
   zval *message_flags;
-  zend_string *key;
-  zval recv_status;
-#endif
   wrapped_grpc_call *call = Z_WRAPPED_GRPC_CALL_P(getThis());
   
   grpc_op ops[8];
@@ -381,7 +271,6 @@
   char *message_str;
   size_t message_len;
 
-
   grpc_metadata_array_init(&metadata);
   grpc_metadata_array_init(&trailing_metadata);
   grpc_metadata_array_init(&recv_metadata);
@@ -396,67 +285,63 @@
     goto cleanup;
   }
 
-#if PHP_MAJOR_VERSION < 7
-
   array_hash = Z_ARRVAL_P(array);
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&value,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_LONG) {
+
+  char *key = NULL;
+  int key_type;
+  PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(array_hash, key, key_type, index,
+                                           value)
+    if (key_type != HASH_KEY_IS_LONG || key != NULL) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "batch keys must be integers", 1 TSRMLS_CC);
       goto cleanup;
     }
     switch(index) {
     case GRPC_OP_SEND_INITIAL_METADATA:
-      if (!create_metadata_array(*value, &metadata)) {
+      if (!create_metadata_array(value, &metadata)) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Bad metadata value given", 1 TSRMLS_CC);
         goto cleanup;
       }
-      ops[op_num].data.send_initial_metadata.count =
-          metadata.count;
-      ops[op_num].data.send_initial_metadata.metadata =
-          metadata.metadata;
+      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) {
+      if (Z_TYPE_P(value) != IS_ARRAY) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Expected an array for send message",
                              1 TSRMLS_CC);
         goto cleanup;
       }
-      message_hash = Z_ARRVAL_PP(value);
-      if (zend_hash_find(message_hash, "flags", sizeof("flags"),
+      message_hash = Z_ARRVAL_P(value);
+      if (php_grpc_zend_hash_find(message_hash, "flags", sizeof("flags"),
                          (void **)&message_flags) == SUCCESS) {
-        if (Z_TYPE_PP(message_flags) != IS_LONG) {
+        if (Z_TYPE_P(message_flags) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Expected an int for message flags",
                                1 TSRMLS_CC);
         }
-        ops[op_num].flags = Z_LVAL_PP(message_flags) & GRPC_WRITE_USED_MASK;
+        ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
       }
-      if (zend_hash_find(message_hash, "message", sizeof("message"),
+      if (php_grpc_zend_hash_find(message_hash, "message", sizeof("message"),
                          (void **)&message_value) != SUCCESS ||
-          Z_TYPE_PP(message_value) != IS_STRING) {
+          Z_TYPE_P(message_value) != IS_STRING) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Expected a string for send message",
                              1 TSRMLS_CC);
         goto cleanup;
       }
       ops[op_num].data.send_message =
-          string_to_byte_buffer(Z_STRVAL_PP(message_value),
-                                Z_STRLEN_PP(message_value));
+          string_to_byte_buffer(Z_STRVAL_P(message_value),
+                                Z_STRLEN_P(message_value));
       break;
     case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
       break;
     case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      status_hash = Z_ARRVAL_PP(value);
-      if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
+      status_hash = Z_ARRVAL_P(value);
+      if (php_grpc_zend_hash_find(status_hash, "metadata", sizeof("metadata"),
                          (void **)&inner_value) == SUCCESS) {
-        if (!create_metadata_array(*inner_value, &trailing_metadata)) {
+        if (!create_metadata_array(inner_value, &trailing_metadata)) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Bad trailing metadata value given",
                                1 TSRMLS_CC);
@@ -467,32 +352,32 @@
         ops[op_num].data.send_status_from_server.trailing_metadata_count =
             trailing_metadata.count;
       }
-      if (zend_hash_find(status_hash, "code", sizeof("code"),
+      if (php_grpc_zend_hash_find(status_hash, "code", sizeof("code"),
                          (void**)&inner_value) == SUCCESS) {
-        if (Z_TYPE_PP(inner_value) != IS_LONG) {
+        if (Z_TYPE_P(inner_value) != IS_LONG) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Status code must be an integer",
                                1 TSRMLS_CC);
           goto cleanup;
         }
         ops[op_num].data.send_status_from_server.status =
-            Z_LVAL_PP(inner_value);
+            Z_LVAL_P(inner_value);
       } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "Integer status code is required",
                              1 TSRMLS_CC);
         goto cleanup;
       }
-      if (zend_hash_find(status_hash, "details", sizeof("details"),
+      if (php_grpc_zend_hash_find(status_hash, "details", sizeof("details"),
                          (void**)&inner_value) == SUCCESS) {
-        if (Z_TYPE_PP(inner_value) != IS_STRING) {
+        if (Z_TYPE_P(inner_value) != IS_STRING) {
           zend_throw_exception(spl_ce_InvalidArgumentException,
                                "Status details must be a string",
                                1 TSRMLS_CC);
           goto cleanup;
         }
         ops[op_num].data.send_status_from_server.status_details =
-            Z_STRVAL_PP(inner_value);
+            Z_STRVAL_P(inner_value);
       } else {
         zend_throw_exception(spl_ce_InvalidArgumentException,
                              "String status details is required",
@@ -527,131 +412,7 @@
     ops[op_num].flags = 0;
     ops[op_num].reserved = NULL;
     op_num++;
-  }
-
-#else
-
-  array_hash = HASH_OF(array);
-  ZEND_HASH_FOREACH_KEY_VAL(array_hash, index, key, value) {
-    if (key) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "batch keys must be integers", 1);
-      goto cleanup;
-    }
-
-    switch(index) {
-    case GRPC_OP_SEND_INITIAL_METADATA:
-      if (!create_metadata_array(value, &metadata)) {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Bad metadata value given", 1);
-        goto cleanup;
-      }
-      ops[op_num].data.send_initial_metadata.count = metadata.count;
-      ops[op_num].data.send_initial_metadata.metadata = metadata.metadata;
-      break;
-    case GRPC_OP_SEND_MESSAGE:
-      if (Z_TYPE_P(value) != IS_ARRAY) {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Expected an array for send message", 1);
-        goto cleanup;
-      }
-      message_hash = HASH_OF(value);
-      if ((message_flags =
-           zend_hash_str_find(message_hash, "flags",
-                              sizeof("flags") - 1)) != NULL) {
-        if (Z_TYPE_P(message_flags) != IS_LONG) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Expected an int for message flags", 1);
-        }
-        ops[op_num].flags = Z_LVAL_P(message_flags) & GRPC_WRITE_USED_MASK;
-      }
-      if ((message_value = zend_hash_str_find(message_hash, "message",
-                                              sizeof("message") - 1))
-          == NULL || Z_TYPE_P(message_value) != IS_STRING) {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Expected a string for send message", 1);
-        goto cleanup;
-      }
-      ops[op_num].data.send_message =
-        string_to_byte_buffer(Z_STRVAL_P(message_value),
-                              Z_STRLEN_P(message_value));
-      break;
-    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-      break;
-    case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      status_hash = HASH_OF(value);
-      if ((inner_value = zend_hash_str_find(status_hash, "metadata",
-                                            sizeof("metadata") - 1))
-          != NULL) {
-        if (!create_metadata_array(inner_value, &trailing_metadata)) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Bad trailing metadata value given", 1);
-          goto cleanup;
-        }
-        ops[op_num].data.send_status_from_server.trailing_metadata =
-          trailing_metadata.metadata;
-        ops[op_num].data.send_status_from_server.trailing_metadata_count =
-          trailing_metadata.count;
-      }
-      if ((inner_value = zend_hash_str_find(status_hash, "code",
-                                            sizeof("code") - 1)) != NULL) {
-        if (Z_TYPE_P(inner_value) != IS_LONG) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Status code must be an integer", 1);
-          goto cleanup;
-        }
-        ops[op_num].data.send_status_from_server.status =
-          Z_LVAL_P(inner_value);
-      } else {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "Integer status code is required", 1);
-        goto cleanup;
-      }
-      if ((inner_value = zend_hash_str_find(status_hash, "details",
-                                            sizeof("details") - 1)) != NULL) {
-        if (Z_TYPE_P(inner_value) != IS_STRING) {
-          zend_throw_exception(spl_ce_InvalidArgumentException,
-                               "Status details must be a string", 1);
-          goto cleanup;
-        }
-        ops[op_num].data.send_status_from_server.status_details =
-          Z_STRVAL_P(inner_value);
-      } else {
-        zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "String status details is required", 1);
-        goto cleanup;
-      }
-      break;
-    case GRPC_OP_RECV_INITIAL_METADATA:
-      ops[op_num].data.recv_initial_metadata = &recv_metadata;
-      break;
-    case GRPC_OP_RECV_MESSAGE:
-      ops[op_num].data.recv_message = &message;
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      ops[op_num].data.recv_status_on_client.trailing_metadata =
-        &recv_trailing_metadata;
-      ops[op_num].data.recv_status_on_client.status = &status;
-      ops[op_num].data.recv_status_on_client.status_details =
-        &status_details;
-      ops[op_num].data.recv_status_on_client.status_details_capacity =
-        &status_details_capacity;
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
-      break;
-    default:
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "Unrecognized key in batch", 1);
-      goto cleanup;
-    }
-    ops[op_num].op = (grpc_op_type)index;
-    ops[op_num].flags = 0;
-    ops[op_num].reserved = NULL;
-    op_num++;
-  } ZEND_HASH_FOREACH_END();
-
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 
   error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
                                 NULL);
@@ -663,7 +424,9 @@
   }
   grpc_completion_queue_pluck(completion_queue, call->wrapped,
                               gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+  zval recv_md;
+#endif
   for (int i = 0; i < op_num; i++) {
     switch(ops[i].op) {
     case GRPC_OP_SEND_INITIAL_METADATA:
@@ -679,73 +442,38 @@
       add_property_bool(result, "send_status", true);
       break;
     case GRPC_OP_RECV_INITIAL_METADATA:
+#if PHP_MAJOR_VERSION < 7
       array = grpc_parse_metadata_array(&recv_metadata TSRMLS_CC);
       add_property_zval(result, "metadata", array);
-      Z_DELREF_P(array);
-      break;
-    case GRPC_OP_RECV_MESSAGE:
-      byte_buffer_to_string(message, &message_str, &message_len);
-      if (message_str == NULL) {
-        add_property_null(result, "message");
-      } else {
-        add_property_stringl(result, "message", message_str, message_len,
-                             false);
-      }
-      break;
-    case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      MAKE_STD_ZVAL(recv_status);
-      object_init(recv_status);
-      array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
-      add_property_zval(recv_status, "metadata", array);
-      Z_DELREF_P(array);
-      add_property_long(recv_status, "code", status);
-      add_property_string(recv_status, "details", status_details, true);
-      add_property_zval(result, "status", recv_status);
-      Z_DELREF_P(recv_status);
-      break;
-    case GRPC_OP_RECV_CLOSE_ON_SERVER:
-      add_property_bool(result, "cancelled", cancelled);
-      break;
-    default:
-      break;
-    }
-  }
 #else
-  zval recv_md;
-  for (int i = 0; i < op_num; i++) {
-    switch(ops[i].op) {
-    case GRPC_OP_SEND_INITIAL_METADATA:
-      add_property_bool(result, "send_metadata", true);
-      break;
-    case GRPC_OP_SEND_MESSAGE:
-      add_property_bool(result, "send_message", true);
-      break;
-    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
-      add_property_bool(result, "send_close", true);
-      break;
-    case GRPC_OP_SEND_STATUS_FROM_SERVER:
-      add_property_bool(result, "send_status", true);
-      break;
-    case GRPC_OP_RECV_INITIAL_METADATA:
       recv_md = *grpc_parse_metadata_array(&recv_metadata);
       add_property_zval(result, "metadata", &recv_md);
+#endif
+      PHP_GRPC_DELREF(array);
       break;
     case GRPC_OP_RECV_MESSAGE:
       byte_buffer_to_string(message, &message_str, &message_len);
       if (message_str == NULL) {
         add_property_null(result, "message");
       } else {
-        add_property_stringl(result, "message", message_str,
-                             message_len);
+        php_grpc_add_property_stringl(result, "message", message_str,
+                                      message_len, false);
       }
       break;
     case GRPC_OP_RECV_STATUS_ON_CLIENT:
-      object_init(&recv_status);
+#if PHP_MAJOR_VERSION < 7
+      array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
+      add_property_zval(recv_status, "metadata", array);
+#else
       recv_md = *grpc_parse_metadata_array(&recv_trailing_metadata);
-      add_property_zval(&recv_status, "metadata", &recv_md);
-      add_property_long(&recv_status, "code", status);
-      add_property_string(&recv_status, "details", status_details);
-      add_property_zval(result, "status", &recv_status);
+      add_property_zval(recv_status, "metadata", &recv_md);
+#endif
+      PHP_GRPC_DELREF(array);
+      add_property_long(recv_status, "code", status);
+      php_grpc_add_property_string(recv_status, "details", status_details,
+                                   true);
+      add_property_zval(result, "status", recv_status);
+      PHP_GRPC_DELREF(recv_status);
       break;
     case GRPC_OP_RECV_CLOSE_ON_SERVER:
       add_property_bool(result, "cancelled", cancelled);
@@ -754,7 +482,6 @@
       break;
     }
   }
-#endif
 
 cleanup:
   grpc_metadata_array_destroy(&metadata);
@@ -833,10 +560,5 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_call, call_ce_handlers);
 }
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 29762af..6921a5d 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -52,69 +52,28 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_call_credentials;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers call_credentials_ce_handlers;
+#endif
 
 /* 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 =
-      (wrapped_grpc_call_credentials *)object;
-  if (creds->wrapped != NULL) {
-    grpc_call_credentials_release(creds->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call_credentials)
+  if (p->wrapped != NULL) {
+    grpc_call_credentials_release(p->wrapped);
   }
-  zend_object_std_dtor(&creds->std TSRMLS_CC);
-  efree(creds);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_call_credentials to be
  * associated with an object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_call_credentials(
+php_grpc_zend_object create_wrapped_grpc_call_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_call_credentials *intern;
-
-  intern = (wrapped_grpc_call_credentials *)emalloc(
-      sizeof(wrapped_grpc_call_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_call_credentials));
-
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_call_credentials, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call_credentials,
+                             call_credentials_ce_handlers);
 }
 
-#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;
-}
-
-#endif
-
 zval *grpc_php_wrap_call_credentials(grpc_call_credentials
                                      *wrapped TSRMLS_DC) {
   zval *credentials_object;
@@ -276,13 +235,6 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_call_credentials,
+                        call_credentials_ce_handlers);
 }
diff --git a/src/php/ext/grpc/call_credentials.h b/src/php/ext/grpc/call_credentials.h
index 822d077..c1d85c0 100755
--- a/src/php/ext/grpc/call_credentials.h
+++ b/src/php/ext/grpc/call_credentials.h
@@ -63,15 +63,13 @@
 #else
 
 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));
+*wrapped_grpc_call_credentials_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)))
+  wrapped_grpc_call_credentials_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 18ebcab..b5a2c9f 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -56,122 +56,52 @@
 #include "timeval.h"
 
 zend_class_entry *grpc_ce_channel;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers channel_ce_handlers;
+#endif
 
 /* 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);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
+  if (p->wrapped != NULL) {
+    grpc_channel_destroy(p->wrapped);
   }
-  zend_object_std_dtor(&channel->std TSRMLS_CC);
-  efree(channel);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_channel to be associated with an
  * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_channel(zend_class_entry *class_type
-                                                  TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_channel *intern;
-  intern = (wrapped_grpc_channel *)emalloc(sizeof(wrapped_grpc_channel));
-  memset(intern, 0, sizeof(wrapped_grpc_channel));
+php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
+                                                 TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_channel, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel, channel_ce_handlers);
 }
 
-#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;
-}
-
-#endif
-
 void php_grpc_read_args_array(zval *args_array,
                               grpc_channel_args *args TSRMLS_DC) {
   HashTable *array_hash;
   int args_index;
-#if PHP_MAJOR_VERSION < 7
-  HashPosition array_pointer;
-  zval **data;
-  char *key;
-  uint key_len;
-  ulong index;
-#else
-  zval *data;
-  zend_string *key;
-#endif
   array_hash = Z_ARRVAL_P(args_array);
   if (!array_hash) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "array_hash is NULL", 1);
+                         "array_hash is NULL", 1 TSRMLS_CC);
     return;
   }
   args->num_args = zend_hash_num_elements(array_hash);
   args->args = ecalloc(args->num_args, sizeof(grpc_arg));
   args_index = 0;
 
-#if PHP_MAJOR_VERSION < 7
-  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void **)&data,
-                                     &array_pointer) == SUCCESS;
-       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
-    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
+  char *key = NULL;
+  zval *data;
+  int key_type;
+
+  PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type, data)
+    if (key_type != HASH_KEY_IS_STRING) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "args keys must be strings", 1 TSRMLS_CC);
       return;
     }
     args->args[args_index].key = key;
-    switch (Z_TYPE_P(*data)) {
-    case IS_LONG:
-      args->args[args_index].value.integer = (int)Z_LVAL_P(*data);
-      args->args[args_index].type = GRPC_ARG_INTEGER;
-      break;
-    case IS_STRING:
-      args->args[args_index].value.string = Z_STRVAL_P(*data);
-      args->args[args_index].type = GRPC_ARG_STRING;
-      break;
-    default:
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args values must be int or string", 1 TSRMLS_CC);
-      return;
-    }
-    args_index++;
-  }
-#else
-  ZEND_HASH_FOREACH_STR_KEY_VAL(array_hash, key, data) {
-    if (key == NULL) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args keys must be strings", 1);
-    }
-    args->args[args_index].key = ZSTR_VAL(key);
     switch (Z_TYPE_P(data)) {
     case IS_LONG:
       args->args[args_index].value.integer = (int)Z_LVAL_P(data);
@@ -183,12 +113,11 @@
       break;
     default:
       zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "args values must be int or string", 1);
+                           "args values must be int or string", 1 TSRMLS_CC);
       return;
     }
     args_index++;
-  } ZEND_HASH_FOREACH_END();
-#endif
+  PHP_GRPC_HASH_FOREACH_END()
 }
 
 /**
@@ -200,11 +129,7 @@
  */
 PHP_METHOD(Channel, __construct) {
   wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
-#if PHP_MAJOR_VERSION < 7
-  zval **creds_obj = NULL;
-#else
   zval *creds_obj = NULL;
-#endif
   char *target;
   php_grpc_int target_length;
   zval *args_array = NULL;
@@ -219,43 +144,23 @@
                          "Channel expects a string and an array", 1 TSRMLS_CC);
     return;
   }
-#if PHP_MAJOR_VERSION < 7
   array_hash = Z_ARRVAL_P(args_array);
-  if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
+  if (php_grpc_zend_hash_find(array_hash, "credentials", sizeof("credentials"),
                      (void **)&creds_obj) == SUCCESS) {
-    if (Z_TYPE_P(*creds_obj) == IS_NULL) {
+    if (Z_TYPE_P(creds_obj) == IS_NULL) {
       creds = NULL;
-      zend_hash_del(array_hash, "credentials", 12);
-    } else if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
-        grpc_ce_channel_credentials) {
+      php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
+    } else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
+               grpc_ce_channel_credentials) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
                            "credentials must be a ChannelCredentials object",
                            1 TSRMLS_CC);
       return;
     } else {
-      creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
-          *creds_obj TSRMLS_CC);
-      zend_hash_del(array_hash, "credentials", 12);
-    }
-  }
-#else
-  array_hash = HASH_OF(args_array);
-  if ((creds_obj = zend_hash_str_find(array_hash, "credentials",
-                                      sizeof("credentials") - 1)) != NULL) {
-    if (Z_TYPE_P(creds_obj) == IS_NULL) {
-      creds = NULL;
-      zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
-    } else if (Z_OBJ_P(creds_obj)->ce != grpc_ce_channel_credentials) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "credentials must be a ChannelCredentials object",
-                           1);
-      return;
-    } else {
       creds = Z_WRAPPED_GRPC_CHANNEL_CREDS_P(creds_obj);
-      zend_hash_str_del(array_hash, "credentials", sizeof("credentials") - 1);
+      php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
     }
   }
-#endif
   php_grpc_read_args_array(args_array, &args TSRMLS_CC);
   if (creds == NULL) {
     channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
@@ -311,8 +216,7 @@
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
           &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-        "watchConnectivityState expects 1 long 1 timeval",
-        1 TSRMLS_CC);
+        "watchConnectivityState expects 1 long 1 timeval", 1 TSRMLS_CC);
     return;
   }
 
@@ -352,11 +256,5 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel, channel_ce_handlers);
 }
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index 1c2ea5b..0b356aa 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -52,6 +52,9 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_channel_credentials;
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers channel_credentials_ce_handlers;
+#endif
 static char *default_pem_root_certs = NULL;
 
 static grpc_ssl_roots_override_result get_ssl_roots_override(
@@ -63,68 +66,24 @@
   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 =
-      (wrapped_grpc_channel_credentials *)object;
-  if (creds->wrapped != NULL) {
-    grpc_channel_credentials_release(creds->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel_credentials)
+  if (p->wrapped != NULL) {
+    grpc_channel_credentials_release(p->wrapped);
   }
-  zend_object_std_dtor(&creds->std TSRMLS_CC);
-  efree(creds);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_channel_credentials to be
  * associated with an object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_channel_credentials(
+php_grpc_zend_object create_wrapped_grpc_channel_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_channel_credentials *intern;
-
-  intern = (wrapped_grpc_channel_credentials *)emalloc(
-      sizeof(wrapped_grpc_channel_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_channel_credentials));
-
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_channel_credentials, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel_credentials,
+                             channel_credentials_ce_handlers);
 }
 
-#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;
-}
-
-#endif
-
 zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials
                                         *wrapped TSRMLS_DC) {
   zval *credentials_object;
@@ -267,13 +226,6 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel_credentials,
+                        channel_credentials_ce_handlers);
 }
diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h
index 21225db..b043d91 100755
--- a/src/php/ext/grpc/channel_credentials.h
+++ b/src/php/ext/grpc/channel_credentials.h
@@ -63,15 +63,13 @@
 #else
 
 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));
+*wrapped_grpc_channel_credentials_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)))
+  wrapped_grpc_channel_credentials_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
deleted file mode 100644
index daf2ee5..0000000
--- a/src/php/ext/grpc/package.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.9.5" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
- <name>grpc</name>
- <channel>pecl.php.net</channel>
- <summary>A high performance, open source, general RPC framework that puts mobile and HTTP/2 first.</summary>
- <description>Remote Procedure Calls (RPCs) provide a useful abstraction for building distributed applications and services. The libraries in this repository provide a concrete implementation of the gRPC protocol, layered over HTTP/2. These libraries enable communication between clients and servers using any combination of the supported languages.</description>
- <lead>
-  <name>Stanley Cheung</name>
-  <user>stanleycheung</user>
-  <email>grpc-packages@google.com</email>
-  <active>yes</active>
- </lead>
- <date>2016-01-13</date>
- <time>16:06:07</time>
- <version>
-  <release>0.7.0</release>
-  <api>0.7.0</api>
- </version>
- <stability>
-  <release>beta</release>
-  <api>beta</api>
- </stability>
- <license>BSD</license>
- <notes>
-- Breaking change to Credentials class (removed) #3765
-- Replaced by ChannelCredentials and CallCredentials class #3765
-- New plugin based metadata auth API #4394
-- Explicit ChannelCredentials::createInsecure() call
- </notes>
- <contents>
-  <dir baseinstalldir="/" name="/">
-   <file baseinstalldir="/" md5sum="f201d644fdbd8228ffd1d4a69cc44f1f" name="tests/grpc-basic.phpt" role="test" />
-   <file baseinstalldir="/" md5sum="6f19828fb869b7b8a590cbb76b4f996d" name="byte_buffer.c" role="src" />
-   <file baseinstalldir="/" md5sum="c8de0f819499c48adfc8d7f472c0196b" name="byte_buffer.h" role="src" />
-   <file baseinstalldir="/" md5sum="ee7eb7757f9e6f0e36f8f616b6bd0af5" name="call.c" role="src" />
-   <file baseinstalldir="/" md5sum="44c56bd9912d2538cbd6059e3e0452b6" name="call.h" role="src" />
-   <file baseinstalldir="/" md5sum="ff90f6c03ed44b5f4170bf3259a6704e" name="call_credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="3c3860e1d84f43cb6b2fbaa8d2ae1ab7" name="call_credentials.h" role="src" />
-   <file baseinstalldir="/" md5sum="aee9b63f790522aec2c682055240cc61" name="channel.c" role="src" />
-   <file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" />
-   <file baseinstalldir="/" md5sum="1a51c76d0b7b7d3ab570ed7d60c2ea46" name="channel_credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="a86250e03f610ce6c2c7595a84e08821" name="channel_credentials.h" role="src" />
-   <file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" />
-   <file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
-   <file baseinstalldir="/" md5sum="cafed254127007ff2271dad7d56a06c8" name="config.m4" role="src" />
-   <file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
-   <file baseinstalldir="/" md5sum="8847cf67b1b54c981d47ecbb0d139a0c" name="LICENSE" role="doc" />
-   <file baseinstalldir="/" md5sum="3131a8af38fe5918e5409016b89d6cdb" name="php_grpc.c" role="src" />
-   <file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
-   <file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" />
-   <file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
-   <file baseinstalldir="/" md5sum="4b730f06d14cbbb0642bdbd194749595" name="server.h" role="src" />
-   <file baseinstalldir="/" md5sum="34ea881f1fe960d190d0713422cf8916" name="server_credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="9c4b4cc06356a8a39a16a085a9b85996" name="server_credentials.h" role="src" />
-   <file baseinstalldir="/" md5sum="7646ec78cb133f66ba59e03c6f451e39" name="timeval.c" role="src" />
-   <file baseinstalldir="/" md5sum="496e27a100b4d93ca3fb35c924c5e163" name="timeval.h" role="src" />
-  </dir>
- </contents>
- <dependencies>
-  <required>
-   <php>
-    <min>5.5.0</min>
-   </php>
-   <pearinstaller>
-    <min>1.4.0</min>
-   </pearinstaller>
-  </required>
- </dependencies>
- <providesextension>grpc</providesextension>
- <extsrcrelease />
- <changelog>
-  <release>
-   <version>
-    <release>0.5.0</release>
-    <api>0.5.0</api>
-   </version>
-   <stability>
-    <release>alpha</release>
-    <api>alpha</api>
-   </stability>
-   <date>2015-06-16</date>
-   <license>BSD</license>
-   <notes>
-First alpha release
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.5.1</release>
-    <api>0.5.1</api>
-   </version>
-   <stability>
-    <release>alpha</release>
-    <api>alpha</api>
-   </stability>
-   <date>2015-07-09</date>
-   <license>BSD</license>
-   <notes>
-Update to wrap gRPC C Core version 0.10.0
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.6.0</release>
-    <api>0.6.0</api>
-   </version>
-   <stability>
-    <release>beta</release>
-    <api>beta</api>
-   </stability>
-   <date>2015-09-24</date>
-   <license>BSD</license>
-   <notes>
-- support per message compression disable
-- expose per-call host override option
-- expose connectivity API
-- expose channel target and call peer
-- add user-agent
-- update to wrap gRPC C core library beta version 0.11.0
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.6.1</release>
-    <api>0.6.0</api>
-   </version>
-   <stability>
-    <release>beta</release>
-    <api>beta</api>
-   </stability>
-   <date>2015-10-21</date>
-   <license>BSD</license>
-   <notes>
-- fixed undefined constant fatal error when run with apache/nginx #2275
-   </notes>
-  </release>
-  <release>
-   <version>
-    <release>0.7.0</release>
-    <api>0.7.0</api>
-   </version>
-   <stability>
-    <release>beta</release>
-    <api>beta</api>
-   </stability>
-   <date>2016-01-13</date>
-   <license>BSD</license>
-   <notes>
-- Breaking change to Credentials class (removed) #3765
-- Replaced by ChannelCredentials and CallCredentials class #3765
-- New plugin based metadata auth API #4394
-- Explicit ChannelCredentials::createInsecure() call
-   </notes>
-  </release>
- </changelog>
-</package>
diff --git a/src/php/ext/grpc/php7_wrapper.h b/src/php/ext/grpc/php7_wrapper.h
index 58dffc3..fd8d356 100644
--- a/src/php/ext/grpc/php7_wrapper.h
+++ b/src/php/ext/grpc/php7_wrapper.h
@@ -40,6 +40,7 @@
 #define php_grpc_int int
 #define php_grpc_long long
 #define php_grpc_ulong ulong
+#define php_grpc_zend_object zend_object_value
 #define php_grpc_add_property_string(arg, name, context, b) \
   add_property_string(arg, name, context, b)
 #define php_grpc_add_property_stringl(res, name, str, len, b) \
@@ -49,6 +50,7 @@
 
 #define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val, dup)
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) MAKE_STD_ZVAL(pzv)
+#define PHP_GRPC_DELREF(zv) Z_DELREF_P(zv)
 
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
   typedef struct name { \
@@ -56,11 +58,82 @@
 #define PHP_GRPC_WRAP_OBJECT_END(name) \
   } name;
 
+#define PHP_GRPC_FREE_WRAPPED_FUNC_START(class_object) \
+  void free_##class_object(void *object TSRMLS_DC) { \
+    class_object *p = (class_object *)object;
+#define PHP_GRPC_FREE_WRAPPED_FUNC_END() \
+    zend_object_std_dtor(&p->std TSRMLS_CC); \
+    efree(p); \
+  }
+
+#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
+  class_object *intern; \
+  zend_object_value retval; \
+  intern = (class_object *)emalloc(sizeof(class_object)); \
+  memset(intern, 0, sizeof(class_object));
+
+#define PHP_GRPC_FREE_CLASS_OBJECT(class_object, handler) \
+  retval.handle = zend_objects_store_put( \
+    intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \
+    free_##class_object, NULL TSRMLS_CC); \
+  retval.handlers = zend_get_std_object_handlers(); \
+  return retval;
+
+#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
+  zval **tmp_data = NULL; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp_data) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    data = *tmp_data;
+
+#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
+  zval **tmp##key = NULL; \
+  ulong index##key; \
+  uint len##key; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index##key,\
+                                         0, NULL); \
+    data = *tmp##key;
+
+#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index,\
+                                                 data) \
+  zval **tmp##key = NULL; \
+  uint len##key; \
+  for (zend_hash_internal_pointer_reset(ht); \
+       zend_hash_get_current_data(ht, (void**)&tmp##key) == SUCCESS; \
+       zend_hash_move_forward(ht)) { \
+    key_type = zend_hash_get_current_key_ex(ht, &key, &len##key, &index,\
+                                         0, NULL); \
+    data = *tmp##key;
+
+#define PHP_GRPC_HASH_FOREACH_END() }
+
+static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
+                                          void **value) {
+  zval **data = NULL;
+  if (zend_hash_find(ht, key, len, (void **)&data) == SUCCESS) {
+    *value = *data;
+    return SUCCESS;
+  } else {
+    *value = NULL;
+    return FAILURE;
+  }
+}
+
+#define php_grpc_zend_hash_del zend_hash_del
+
+#define PHP_GRPC_GET_CLASS_ENTRY(object) zend_get_class_entry(object TSRMLS_CC)
+
+#define PHP_GRPC_INIT_HANDLER(class_object, handler_name)
+
 #else
 
 #define php_grpc_int size_t
 #define php_grpc_long zend_long
 #define php_grpc_ulong zend_ulong
+#define php_grpc_zend_object zend_object*
 #define php_grpc_add_property_string(arg, name, context, b) \
   add_property_string(arg, name, context)
 #define php_grpc_add_property_stringl(res, name, str, len, b) \
@@ -72,6 +145,7 @@
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
   zval _stack_zval_##pzv; \
   pzv = &(_stack_zval_##pzv)
+#define PHP_GRPC_DELREF(zv)
 
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
   typedef struct name {
@@ -79,6 +153,66 @@
     zend_object std; \
   } name;
 
+#define WRAPPED_OBJECT_FROM_OBJ(class_object, obj) \
+  class_object##_from_obj(obj);
+
+#define PHP_GRPC_FREE_WRAPPED_FUNC_START(class_object) \
+  static void free_##class_object(zend_object *object) { \
+    class_object *p = WRAPPED_OBJECT_FROM_OBJ(class_object, object)
+#define PHP_GRPC_FREE_WRAPPED_FUNC_END() \
+    zend_object_std_dtor(&p->std); \
+  }
+
+#define PHP_GRPC_ALLOC_CLASS_OBJECT(class_object) \
+  class_object *intern; \
+  intern = ecalloc(1, sizeof(class_object) + \
+                   zend_object_properties_size(class_type));
+
+#define PHP_GRPC_FREE_CLASS_OBJECT(class_object, handler) \
+  intern->std.handlers = &handler; \
+  return &intern->std;
+
+#define PHP_GRPC_HASH_FOREACH_VAL_START(ht, data) \
+  ZEND_HASH_FOREACH_VAL(ht, data) {
+
+#define PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(ht, key, key_type, data) \
+  zend_string *(zs_##key); \
+  ZEND_HASH_FOREACH_STR_KEY_VAL(ht, (zs_##key), data) { \
+    if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
+    else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
+
+#define PHP_GRPC_HASH_FOREACH_LONG_KEY_VAL_START(ht, key, key_type, index, \
+                                                 data) \
+  zend_string *(zs_##key); \
+  ZEND_HASH_FOREACH_KEY_VAL(ht, index, zs_##key, data) { \
+    if ((zs_##key) == NULL) {key = NULL; key_type = HASH_KEY_IS_LONG;} \
+    else {key = (zs_##key)->val; key_type = HASH_KEY_IS_STRING;}
+
+#define PHP_GRPC_HASH_FOREACH_END() } ZEND_HASH_FOREACH_END();
+
+static inline int php_grpc_zend_hash_find(HashTable *ht, char *key, int len,
+                                          void **value) {
+  zval *value_tmp = zend_hash_str_find(ht, key, len -1);
+  if (value_tmp == NULL) {
+    return FAILURE;
+  } else {
+    *value = (void *)value_tmp;
+    return SUCCESS;
+  }
+}
+
+static inline int php_grpc_zend_hash_del(HashTable *ht, char *key, int len) {
+  return zend_hash_str_del(ht, key, len - 1);
+}
+
+#define PHP_GRPC_GET_CLASS_ENTRY(object) Z_OBJ_P(object)->ce
+
+#define PHP_GRPC_INIT_HANDLER(class_object, handler_name) \
+  memcpy(&handler_name, zend_get_std_object_handlers(), \
+         sizeof(zend_object_handlers)); \
+  handler_name.offset = XtOffsetOf(class_object, std); \
+  handler_name.free_obj = free_##class_object
+
 #endif /* PHP_MAJOR_VERSION */
 
 #endif /* PHP7_WRAPPER_GRPC_H */
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 577b707..fc20c42 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -57,73 +57,31 @@
 #include "timeval.h"
 
 zend_class_entry *grpc_ce_server;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers server_ce_handlers;
+#endif
 
 /* 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;
-  if (server->wrapped != NULL) {
-    grpc_server_shutdown_and_notify(server->wrapped, completion_queue, NULL);
-    grpc_server_cancel_all_calls(server->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server)
+  if (p->wrapped != NULL) {
+    grpc_server_shutdown_and_notify(p->wrapped, completion_queue, NULL);
+    grpc_server_cancel_all_calls(p->wrapped);
     grpc_completion_queue_pluck(completion_queue, NULL,
                                 gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-    grpc_server_destroy(server->wrapped);
+    grpc_server_destroy(p->wrapped);
   }
-  zend_object_std_dtor(&server->std TSRMLS_CC);
-  efree(server);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_call to be associated with an object
  * of a class specified by class_type */
-zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
-                                                 TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_server *intern;
-
-  intern = (wrapped_grpc_server *)emalloc(sizeof(wrapped_grpc_server));
-  memset(intern, 0, sizeof(wrapped_grpc_server));
-
+php_grpc_zend_object create_wrapped_grpc_server(zend_class_entry *class_type
+                                                TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_server, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server, server_ce_handlers);
 }
 
-#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)
@@ -275,7 +233,7 @@
   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_FE_END
 };
 
 void grpc_init_server(TSRMLS_D) {
@@ -283,10 +241,5 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_server, server_ce_handlers);
 }
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index 02ef1f7..a635bc1 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -66,8 +66,7 @@
                                 XtOffsetOf(wrapped_grpc_server, std));
 }
 
-#define Z_WRAPPED_GRPC_SERVER_P(zv) \
-  wrapped_grpc_server_from_obj(Z_OBJ_P((zv)))
+#define Z_WRAPPED_GRPC_SERVER_P(zv) wrapped_grpc_server_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 46416f5..b05896a 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -50,69 +50,28 @@
 #include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_server_credentials;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers server_credentials_ce_handlers;
+#endif
 
 /* 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 =
-      (wrapped_grpc_server_credentials *)object;
-  if (creds->wrapped != NULL) {
-    grpc_server_credentials_release(creds->wrapped);
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_server_credentials)
+  if (p->wrapped != NULL) {
+    grpc_server_credentials_release(p->wrapped);
   }
-  zend_object_std_dtor(&creds->std TSRMLS_CC);
-  efree(creds);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instace of wrapped_grpc_server_credentials to be associated
  * with an object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_server_credentials(
+php_grpc_zend_object create_wrapped_grpc_server_credentials(
     zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_server_credentials *intern;
-
-  intern = (wrapped_grpc_server_credentials *)emalloc(
-      sizeof(wrapped_grpc_server_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_server_credentials));
-
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_server_credentials);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_server_credentials, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_server_credentials,
+                             server_credentials_ce_handlers);
 }
 
-#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;
-}
-
-#endif
-
 zval *grpc_php_wrap_server_credentials(grpc_server_credentials
                                        *wrapped TSRMLS_DC) {
   zval *server_credentials_object;
@@ -163,7 +122,7 @@
 static zend_function_entry server_credentials_methods[] = {
   PHP_ME(ServerCredentials, createSsl, NULL,
          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-   PHP_FE_END
+  PHP_FE_END
  };
 
 void grpc_init_server_credentials(TSRMLS_D) {
@@ -171,13 +130,6 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_server_credentials,
+                        server_credentials_ce_handlers);
 }
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index 2a90aa6..6781a61 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -63,13 +63,13 @@
 #else
 
 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));
+*wrapped_grpc_server_credentials_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)))
+  wrapped_grpc_server_credentials_from_obj(Z_OBJ_P((zv)))
 
 #endif /* PHP_MAJOR_VERSION */
 
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 7d1ee21..e145d96 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -51,57 +51,24 @@
 #include <grpc/support/time.h>
 
 zend_class_entry *grpc_ce_timeval;
-
-#if PHP_MAJOR_VERSION < 7
+#if PHP_MAJOR_VERSION >= 7
+static zend_object_handlers timeval_ce_handlers;
+#endif
 
 /* Frees and destroys an instance of wrapped_grpc_call */
-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);
-}
+PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_timeval)
+PHP_GRPC_FREE_WRAPPED_FUNC_END()
 
 /* Initializes an instance of wrapped_grpc_timeval to be associated with an
  * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_timeval(zend_class_entry *class_type
-                                                  TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_timeval *intern;
-  intern = (wrapped_grpc_timeval *)emalloc(sizeof(wrapped_grpc_timeval));
-  memset(intern, 0, sizeof(wrapped_grpc_timeval));
+php_grpc_zend_object create_wrapped_grpc_timeval(zend_class_entry *class_type
+                                                 TSRMLS_DC) {
+  PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_timeval);
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_timeval, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
+  PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_timeval, timeval_ce_handlers);
 }
 
-#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;
-}
-
-#endif
-
 zval *grpc_php_wrap_timeval(gpr_timespec wrapped TSRMLS_DC) {
   zval *timeval_object;
   PHP_GRPC_MAKE_STD_ZVAL(timeval_object);
@@ -311,13 +278,7 @@
   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
+  PHP_GRPC_INIT_HANDLER(wrapped_grpc_timeval, timeval_ce_handlers);
 }
 
 void grpc_shutdown_timeval(TSRMLS_D) {}
diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml
index 34bb477..0f61ccf 100644
--- a/src/ruby/.rubocop.yml
+++ b/src/ruby/.rubocop.yml
@@ -5,8 +5,8 @@
 AllCops:
   Exclude:
     - 'bin/apis/**/*'
-    - 'bin/math.rb'
-    - 'bin/math_services.rb'
+    - 'bin/math_pb.rb'
+    - 'bin/math_services_pb.rb'
     - 'pb/grpc/health/v1/*'
     - 'pb/test/**/*'
 
diff --git a/src/ruby/bin/math_client.rb b/src/ruby/bin/math_client.rb
index d7e00e4..1f238a7 100755
--- a/src/ruby/bin/math_client.rb
+++ b/src/ruby/bin/math_client.rb
@@ -40,7 +40,7 @@
 $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
 
 require 'grpc'
-require 'math_services'
+require 'math_services_pb'
 require 'optparse'
 
 include GRPC::Core::TimeConsts
diff --git a/src/ruby/bin/math.rb b/src/ruby/bin/math_pb.rb
old mode 100755
new mode 100644
similarity index 100%
rename from src/ruby/bin/math.rb
rename to src/ruby/bin/math_pb.rb
diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb
index 1ee4c56..751a6eb 100755
--- a/src/ruby/bin/math_server.rb
+++ b/src/ruby/bin/math_server.rb
@@ -42,7 +42,7 @@
 require 'forwardable'
 require 'grpc'
 require 'logger'
-require 'math_services'
+require 'math_services_pb'
 require 'optparse'
 
 # RubyLogger defines a logger for gRPC based on the standard ruby logger.
diff --git a/src/ruby/bin/math_services.rb b/src/ruby/bin/math_services_pb.rb
old mode 100755
new mode 100644
similarity index 98%
rename from src/ruby/bin/math_services.rb
rename to src/ruby/bin/math_services_pb.rb
index 2b97602..2ba1825
--- a/src/ruby/bin/math_services.rb
+++ b/src/ruby/bin/math_services_pb.rb
@@ -32,7 +32,7 @@
 #
 
 require 'grpc'
-require 'math'
+require 'math_pb'
 
 module Math
   module Math
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
index f7310d9..4bce174 100644
--- a/src/ruby/pb/grpc/health/checker.rb
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'grpc/health/v1/health_services'
+require 'grpc/health/v1/health_services_pb'
 require 'thread'
 
 module Grpc
diff --git a/src/ruby/pb/grpc/health/v1/health.rb b/src/ruby/pb/grpc/health/v1/health_pb.rb
similarity index 100%
rename from src/ruby/pb/grpc/health/v1/health.rb
rename to src/ruby/pb/grpc/health/v1/health_pb.rb
diff --git a/src/ruby/pb/grpc/health/v1/health_services.rb b/src/ruby/pb/grpc/health/v1/health_services_pb.rb
similarity index 97%
rename from src/ruby/pb/grpc/health/v1/health_services.rb
rename to src/ruby/pb/grpc/health/v1/health_services_pb.rb
index 68a3956..8cc01e9 100644
--- a/src/ruby/pb/grpc/health/v1/health_services.rb
+++ b/src/ruby/pb/grpc/health/v1/health_services_pb.rb
@@ -32,7 +32,7 @@
 #
 
 require 'grpc'
-require 'grpc/health/v1/health'
+require 'grpc/health/v1/health_pb'
 
 module Grpc
   module Health
diff --git a/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb b/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb
similarity index 92%
rename from src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb
rename to src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb
index eb523ff..e51c2f0 100644
--- a/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services.rb
+++ b/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb
@@ -1,5 +1,5 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: grpc/testing/duplicate/echo_duplicate.proto for package 'grpc.testing.duplicate'
+# Source: src/proto/grpc/testing/duplicate/echo_duplicate.proto for package 'grpc.testing.duplicate'
 # Original file comments:
 # Copyright 2015, Google Inc.
 # All rights reserved.
@@ -34,7 +34,7 @@
 #
 
 require 'grpc'
-require 'grpc/testing/duplicate/echo_duplicate'
+require 'src/proto/grpc/testing/duplicate/echo_duplicate_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/pb/grpc/testing/metrics.rb b/src/ruby/pb/grpc/testing/metrics_pb.rb
similarity index 94%
rename from src/ruby/pb/grpc/testing/metrics.rb
rename to src/ruby/pb/grpc/testing/metrics_pb.rb
index 3b3c8cd..77b6c90 100644
--- a/src/ruby/pb/grpc/testing/metrics.rb
+++ b/src/ruby/pb/grpc/testing/metrics_pb.rb
@@ -1,5 +1,5 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: grpc/testing/metrics.proto
+# source: src/proto/grpc/testing/metrics.proto
 
 require 'google/protobuf'
 
diff --git a/src/ruby/pb/grpc/testing/metrics_services.rb b/src/ruby/pb/grpc/testing/metrics_services_pb.rb
similarity index 95%
rename from src/ruby/pb/grpc/testing/metrics_services.rb
rename to src/ruby/pb/grpc/testing/metrics_services_pb.rb
index 467b7b3..e46366b 100644
--- a/src/ruby/pb/grpc/testing/metrics_services.rb
+++ b/src/ruby/pb/grpc/testing/metrics_services_pb.rb
@@ -1,5 +1,5 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: grpc/testing/metrics.proto for package 'grpc.testing'
+# Source: src/proto/grpc/testing/metrics.proto for package 'grpc.testing'
 # Original file comments:
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
@@ -38,7 +38,7 @@
 # service.
 
 require 'grpc'
-require 'grpc/testing/metrics'
+require 'src/proto/grpc/testing/metrics_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/pb/src/proto/grpc/testing/empty.rb b/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb
similarity index 100%
rename from src/ruby/pb/src/proto/grpc/testing/empty.rb
rename to src/ruby/pb/src/proto/grpc/testing/empty_pb.rb
diff --git a/src/ruby/pb/src/proto/grpc/testing/messages.rb b/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb
similarity index 100%
rename from src/ruby/pb/src/proto/grpc/testing/messages.rb
rename to src/ruby/pb/src/proto/grpc/testing/messages_pb.rb
diff --git a/src/ruby/pb/src/proto/grpc/testing/test.rb b/src/ruby/pb/src/proto/grpc/testing/test_pb.rb
similarity index 72%
rename from src/ruby/pb/src/proto/grpc/testing/test.rb
rename to src/ruby/pb/src/proto/grpc/testing/test_pb.rb
index 245b5ce..2cc9863 100644
--- a/src/ruby/pb/src/proto/grpc/testing/test.rb
+++ b/src/ruby/pb/src/proto/grpc/testing/test_pb.rb
@@ -3,8 +3,8 @@
 
 require 'google/protobuf'
 
-require 'src/proto/grpc/testing/empty'
-require 'src/proto/grpc/testing/messages'
+require 'src/proto/grpc/testing/empty_pb'
+require 'src/proto/grpc/testing/messages_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
 end
 
diff --git a/src/ruby/pb/src/proto/grpc/testing/test_services.rb b/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
similarity index 98%
rename from src/ruby/pb/src/proto/grpc/testing/test_services.rb
rename to src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
index 2652de5..fde328e 100644
--- a/src/ruby/pb/src/proto/grpc/testing/test_services.rb
+++ b/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
@@ -35,7 +35,7 @@
 #
 
 require 'grpc'
-require 'src/proto/grpc/testing/test'
+require 'src/proto/grpc/testing/test_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 4c6d441..1e3ae65 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -52,9 +52,9 @@
 require 'googleauth'
 require 'google/protobuf'
 
-require_relative '../src/proto/grpc/testing/empty'
-require_relative '../src/proto/grpc/testing/messages'
-require_relative '../src/proto/grpc/testing/test_services'
+require_relative '../src/proto/grpc/testing/empty_pb'
+require_relative '../src/proto/grpc/testing/messages_pb'
+require_relative '../src/proto/grpc/testing/test_services_pb'
 
 AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
 
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 11ee3d4..0808121 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -50,9 +50,9 @@
 
 require 'grpc'
 
-require_relative '../src/proto/grpc/testing/empty'
-require_relative '../src/proto/grpc/testing/messages'
-require_relative '../src/proto/grpc/testing/test_services'
+require_relative '../src/proto/grpc/testing/empty_pb'
+require_relative '../src/proto/grpc/testing/messages_pb'
+require_relative '../src/proto/grpc/testing/test_services_pb'
 
 # DebugIsTruncated extends the default Logger to truncate debug messages
 class DebugIsTruncated < Logger
diff --git a/src/ruby/qps/client.rb b/src/ruby/qps/client.rb
index 917b012..7ed648a 100644
--- a/src/ruby/qps/client.rb
+++ b/src/ruby/qps/client.rb
@@ -38,7 +38,7 @@
 
 require 'grpc'
 require 'histogram'
-require 'src/proto/grpc/testing/services_services'
+require 'src/proto/grpc/testing/services_services_pb'
 
 class Poisson
   def interarrival
diff --git a/src/ruby/qps/server.rb b/src/ruby/qps/server.rb
index 52a89ce..cd98ee1 100644
--- a/src/ruby/qps/server.rb
+++ b/src/ruby/qps/server.rb
@@ -38,9 +38,9 @@
 
 require 'grpc'
 require 'qps-common'
-require 'src/proto/grpc/testing/messages'
-require 'src/proto/grpc/testing/services_services'
-require 'src/proto/grpc/testing/stats'
+require 'src/proto/grpc/testing/messages_pb'
+require 'src/proto/grpc/testing/services_services_pb'
+require 'src/proto/grpc/testing/stats_pb'
 
 class BenchmarkServiceImpl < Grpc::Testing::BenchmarkService::Service
   def unary_call(req, _call)
diff --git a/src/ruby/qps/src/proto/grpc/testing/control.rb b/src/ruby/qps/src/proto/grpc/testing/control_pb.rb
similarity index 97%
rename from src/ruby/qps/src/proto/grpc/testing/control.rb
rename to src/ruby/qps/src/proto/grpc/testing/control_pb.rb
index 958fca3..02207a2 100644
--- a/src/ruby/qps/src/proto/grpc/testing/control.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/control_pb.rb
@@ -3,8 +3,8 @@
 
 require 'google/protobuf'
 
-require 'src/proto/grpc/testing/payloads'
-require 'src/proto/grpc/testing/stats'
+require 'src/proto/grpc/testing/payloads_pb'
+require 'src/proto/grpc/testing/stats_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
   add_message "grpc.testing.PoissonParams" do
     optional :offered_load, :double, 1
@@ -109,6 +109,8 @@
     repeated :server_stats, :message, 4, "grpc.testing.ServerStats"
     repeated :server_cores, :int32, 5
     optional :summary, :message, 6, "grpc.testing.ScenarioResultSummary"
+    repeated :client_success, :bool, 7
+    repeated :server_success, :bool, 8
   end
   add_enum "grpc.testing.ClientType" do
     value :SYNC_CLIENT, 0
diff --git a/src/ruby/qps/src/proto/grpc/testing/messages.rb b/src/ruby/qps/src/proto/grpc/testing/messages_pb.rb
similarity index 100%
rename from src/ruby/qps/src/proto/grpc/testing/messages.rb
rename to src/ruby/qps/src/proto/grpc/testing/messages_pb.rb
diff --git a/src/ruby/qps/src/proto/grpc/testing/payloads.rb b/src/ruby/qps/src/proto/grpc/testing/payloads_pb.rb
similarity index 100%
rename from src/ruby/qps/src/proto/grpc/testing/payloads.rb
rename to src/ruby/qps/src/proto/grpc/testing/payloads_pb.rb
diff --git a/src/ruby/qps/src/proto/grpc/testing/services.rb b/src/ruby/qps/src/proto/grpc/testing/services_pb.rb
similarity index 72%
rename from src/ruby/qps/src/proto/grpc/testing/services.rb
rename to src/ruby/qps/src/proto/grpc/testing/services_pb.rb
index b2675c2..5ce13bf 100644
--- a/src/ruby/qps/src/proto/grpc/testing/services.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/services_pb.rb
@@ -3,8 +3,8 @@
 
 require 'google/protobuf'
 
-require 'src/proto/grpc/testing/messages'
-require 'src/proto/grpc/testing/control'
+require 'src/proto/grpc/testing/messages_pb'
+require 'src/proto/grpc/testing/control_pb'
 Google::Protobuf::DescriptorPool.generated_pool.build do
 end
 
diff --git a/src/ruby/qps/src/proto/grpc/testing/services_services.rb b/src/ruby/qps/src/proto/grpc/testing/services_services_pb.rb
similarity index 98%
rename from src/ruby/qps/src/proto/grpc/testing/services_services.rb
rename to src/ruby/qps/src/proto/grpc/testing/services_services_pb.rb
index 94b9a1e..bdbb9c8 100644
--- a/src/ruby/qps/src/proto/grpc/testing/services_services.rb
+++ b/src/ruby/qps/src/proto/grpc/testing/services_services_pb.rb
@@ -34,7 +34,7 @@
 # of unary/streaming requests/responses.
 
 require 'grpc'
-require 'src/proto/grpc/testing/services'
+require 'src/proto/grpc/testing/services_pb'
 
 module Grpc
   module Testing
diff --git a/src/ruby/qps/src/proto/grpc/testing/stats.rb b/src/ruby/qps/src/proto/grpc/testing/stats_pb.rb
similarity index 100%
rename from src/ruby/qps/src/proto/grpc/testing/stats.rb
rename to src/ruby/qps/src/proto/grpc/testing/stats_pb.rb
diff --git a/src/ruby/qps/worker.rb b/src/ruby/qps/worker.rb
index 665fb86..12b8087 100755
--- a/src/ruby/qps/worker.rb
+++ b/src/ruby/qps/worker.rb
@@ -44,7 +44,7 @@
 require 'client'
 require 'qps-common'
 require 'server'
-require 'src/proto/grpc/testing/services_services'
+require 'src/proto/grpc/testing/services_services_pb'
 
 class WorkerServiceImpl < Grpc::Testing::WorkerService::Service
   def cpu_cores
diff --git a/src/ruby/spec/pb/duplicate/codegen_spec.rb b/src/ruby/spec/pb/duplicate/codegen_spec.rb
index 54c136c..ea02409 100644
--- a/src/ruby/spec/pb/duplicate/codegen_spec.rb
+++ b/src/ruby/spec/pb/duplicate/codegen_spec.rb
@@ -44,7 +44,7 @@
       # Get the current content
       service_path = File.join(root_dir, 'src', 'ruby', 'pb', 'grpc',
                                'testing', 'duplicate',
-                               'echo_duplicate_services.rb')
+                               'echo_duplicate_services_pb.rb')
       want = nil
       File.open(service_path) { |f| want = f.read }
 
@@ -54,7 +54,7 @@
       got = nil
       Dir.mktmpdir do |tmp_dir|
         gen_out = File.join(tmp_dir, 'src', 'proto', 'grpc', 'testing',
-                            'duplicate', 'echo_duplicate_services.rb')
+                            'duplicate', 'echo_duplicate_services_pb.rb')
         pid = spawn(
           'protoc',
           '-I.',
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index de11c9f..1b2fa96 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 require 'grpc'
-require 'grpc/health/v1/health'
+require 'grpc/health/v1/health_pb'
 require 'grpc/health/checker'
 require 'open3'
 require 'tmpdir'
@@ -43,7 +43,7 @@
       skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen'
     else
       it 'should already be loaded indirectly i.e, used by the other specs' do
-        expect(require('grpc/health/v1/health_services')).to be(false)
+        expect(require('grpc/health/v1/health_services_pb')).to be(false)
       end
 
       it 'should have the same content as created by code generation' do
@@ -52,7 +52,7 @@
 
         # Get the current content
         service_path = File.join(root_dir, 'ruby', 'pb', 'grpc',
-                                 'health', 'v1', 'health_services.rb')
+                                 'health', 'v1', 'health_services_pb.rb')
         want = nil
         File.open(service_path) { |f| want = f.read }
 
@@ -62,7 +62,7 @@
         got = nil
         Dir.mktmpdir do |tmp_dir|
           gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1',
-                              'health_services.rb')
+                              'health_services_pb.rb')
           pid = spawn(
             'protoc',
             '-I.',
diff --git a/src/ruby/stress/metrics_server.rb b/src/ruby/stress/metrics_server.rb
index 13638c4..2b7f785 100644
--- a/src/ruby/stress/metrics_server.rb
+++ b/src/ruby/stress/metrics_server.rb
@@ -27,8 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require_relative '../pb/grpc/testing/metrics.rb'
-require_relative '../pb/grpc/testing/metrics_services.rb'
+require_relative '../pb/grpc/testing/metrics_pb.rb'
+require_relative '../pb/grpc/testing/metrics_services_pb.rb'
 
 class Gauge
   def get_name
diff --git a/src/ruby/tools/bin/grpc_tools_ruby_protoc.rb b/src/ruby/tools/bin/grpc_tools_ruby_protoc
similarity index 79%
rename from src/ruby/tools/bin/grpc_tools_ruby_protoc.rb
rename to src/ruby/tools/bin/grpc_tools_ruby_protoc
index 3a2a5b8..dab06e7 100755
--- a/src/ruby/tools/bin/grpc_tools_ruby_protoc.rb
+++ b/src/ruby/tools/bin/grpc_tools_ruby_protoc
@@ -32,10 +32,17 @@
 
 require_relative '../os_check'
 
-protoc_name = 'protoc' + RbConfig::CONFIG['EXEEXT']
+ext = RbConfig::CONFIG['EXEEXT']
 
-protoc_path = File.join(File.dirname(__FILE__),
-                        RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name,
-                        protoc_name)
+protoc_name = 'protoc' + ext
 
-exec([ protoc_path, protoc_path ], *ARGV)
+plugin_name = 'grpc_ruby_plugin' + ext
+
+protoc_dir = File.join(File.dirname(__FILE__),
+                       RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name)
+
+protoc_path = File.join(protoc_dir, protoc_name)
+
+plugin_path = File.join(protoc_dir, plugin_name)
+
+exec([ protoc_path, protoc_path ], "--plugin=protoc-gen-grpc=#{plugin_path}", *ARGV)
diff --git a/src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin.rb b/src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin
similarity index 100%
rename from src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin.rb
rename to src/ruby/tools/bin/grpc_tools_ruby_protoc_plugin
diff --git a/src/ruby/tools/grpc-tools.gemspec b/src/ruby/tools/grpc-tools.gemspec
index 9fa4b66..68e2a7a 100644
--- a/src/ruby/tools/grpc-tools.gemspec
+++ b/src/ruby/tools/grpc-tools.gemspec
@@ -18,5 +18,5 @@
 
   s.platform = Gem::Platform::RUBY
 
-  s.executables = %w( grpc_tools_ruby_protoc.rb grpc_tools_ruby_protoc_plugin.rb )
+  s.executables = %w( grpc_tools_ruby_protoc grpc_tools_ruby_protoc_plugin )
 end
diff --git a/templates/package.xml.template b/templates/package.xml.template
index 76c6fff..87b1038 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -12,7 +12,7 @@
     <email>grpc-packages@google.com</email>
     <active>yes</active>
    </lead>
-   <date>2016-07-21</date>
+   <date>2016-07-28</date>
    <time>16:06:07</time>
    <version>
     <release>${settings.php_version.php()}</release>
@@ -24,7 +24,7 @@
    </stability>
    <license>BSD</license>
    <notes>
-  - PHP7 Support #7464
+  - PHP7 Support continued, reduce code duplication #7543
    </notes>
    <contents>
     <dir baseinstalldir="/" name="/">
@@ -234,5 +234,20 @@
   - PHP7 Support #7464
      </notes>
     </release>
+    <release>
+     <version>
+      <release>1.0.0RC3</release>
+      <api>1.0.0RC3</api>
+     </version>
+     <stability>
+      <release>stable</release>
+      <api>stable</api>
+     </stability>
+     <date>2016-07-28</date>
+     <license>BSD</license>
+     <notes>
+  - PHP7 Support continued, reduce code duplication #7543
+     </notes>
+    </release>
    </changelog>
   </package>
diff --git a/templates/src/csharp/Grpc.Core.Tests/project.json.template b/templates/src/csharp/Grpc.Core.Tests/project.json.template
index bc9fa3e..d1ab931 100644
--- a/templates/src/csharp/Grpc.Core.Tests/project.json.template
+++ b/templates/src/csharp/Grpc.Core.Tests/project.json.template
@@ -8,7 +8,10 @@
       },
       "Newtonsoft.Json": "8.0.3",
       "NUnit": "3.2.0",
-      "NUnitLite": "3.2.0-*"
+      "NUnitLite": "3.2.0-*",
+      "NUnit.ConsoleRunner": "3.2.0",
+      "OpenCover": "4.6.519",
+      "ReportGenerator": "2.4.4.0"
     },
     "frameworks": {
       "net45": { },
diff --git a/templates/src/node/health_check/package.json.template b/templates/src/node/health_check/package.json.template
index 1248ced..96b9748 100644
--- a/templates/src/node/health_check/package.json.template
+++ b/templates/src/node/health_check/package.json.template
@@ -21,11 +21,11 @@
       "lodash": "^3.9.3",
       "google-protobuf": "^3.0.0-alpha.5"
     },
-    "files": {
+    "files": [
       "LICENSE",
       "health.js",
       "v1"
-    },
+    ],
     "main": "src/node/index.js",
     "license": "BSD-3-Clause"
   }
diff --git a/test/cpp/end2end/server_builder_plugin_test.cc b/test/cpp/end2end/server_builder_plugin_test.cc
index 778a2be..b967a5d 100644
--- a/test/cpp/end2end/server_builder_plugin_test.cc
+++ b/test/cpp/end2end/server_builder_plugin_test.cc
@@ -191,7 +191,7 @@
     // we run some tests without a service, and for those we need to supply a
     // frequently polled completion queue
     cq_ = builder_->AddCompletionQueue();
-    cq_thread_ = grpc::thread(std::bind(&ServerBuilderPluginTest::RunCQ, this));
+    cq_thread_ = new grpc::thread(&ServerBuilderPluginTest::RunCQ, this);
     server_ = builder_->BuildAndStart();
     EXPECT_TRUE(CheckPresent());
   }
@@ -209,7 +209,8 @@
     EXPECT_TRUE(plugin->finish_is_called());
     server_->Shutdown();
     cq_->Shutdown();
-    cq_thread_.join();
+    cq_thread_->join();
+    delete cq_thread_;
   }
 
   string to_string(const int number) {
@@ -224,7 +225,7 @@
   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
   std::unique_ptr<ServerCompletionQueue> cq_;
   std::unique_ptr<Server> server_;
-  grpc::thread cq_thread_;
+  grpc::thread* cq_thread_;
   TestServiceImpl service_;
   int port_;
 
diff --git a/tools/run_tests/pre_build_csharp.bat b/tools/run_tests/pre_build_csharp.bat
index e7131d5..580d563 100644
--- a/tools/run_tests/pre_build_csharp.bat
+++ b/tools/run_tests/pre_build_csharp.bat
@@ -38,8 +38,61 @@
 set NUGET=C:\nuget\nuget.exe
 
 if exist %NUGET% (
+  @rem Restore Grpc packages by packages since Nuget client 3.4.4 doesnt support restore
+  @rem by solution
+  @rem Moving into each directory to let the restores work with both nuget 3.4 and 2.8
   %NUGET% restore vsprojects/grpc_csharp_ext.sln || goto :error
-  %NUGET% restore src/csharp/Grpc.sln || goto :error
+
+  cd src/csharp
+
+  cd Grpc.Auth || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Core || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Core.Tests || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Examples.MathClient || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Examples.MathServer || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.Examples || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.HealthCheck.Tests || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.HealthCheck || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting.Client || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting.QpsWorker || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting.StressClient || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+  cd ..
+
+  cd Grpc.IntegrationTesting || goto :error
+  %NUGET% restore -PackagesDirectory ../packages || goto :error
+
+  cd /d %~dp0\..\.. || goto :error
 )
 
 endlocal
diff --git a/tools/run_tests/pre_build_csharp.sh b/tools/run_tests/pre_build_csharp.sh
index 3ff1a4e..0fd3b92 100755
--- a/tools/run_tests/pre_build_csharp.sh
+++ b/tools/run_tests/pre_build_csharp.sh
@@ -37,5 +37,54 @@
 
 if [ -x "$(command -v nuget)" ]
 then
-  nuget restore Grpc.sln
+  # Restoring Nuget packages by packages rather than by solution because of
+  # inability to restore by solution with Nuget client 3.4.4
+  # Moving into each directory to let the restores work with nuget 3.4 and 2.8
+  cd Grpc.Auth
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Core.Tests
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Core
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Examples.MathClient
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Examples.MathServer
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.Examples
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.HealthCheck.Tests
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.HealthCheck
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting.Client
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting.QpsWorker
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting.StressClient
+  nuget restore -PackagesDirectory ../packages
+  cd ..
+
+  cd Grpc.IntegrationTesting
+  nuget restore -PackagesDirectory ../packages
+  cd ..
 fi