Ver Fonte

Support PHP generic services (#3269)

* Add php_generic_services option

* Generate PHP generic services

* Respect namespaces for generated PHP services

* Test PHP generated services

* Rename PHP generator service method doc comment function

* Correct phpdoc service method case

* Test namespaced PHP generic services

* Always use the FQCN for PHP generic service input/output

* Add generated_service_test to php test.sh

* Add php service test protos to CI

* Add php service files to php_EXTRA_DIST

* Use Interface suffix for php generic services
Matt A há 8 anos atrás
pai
commit
9e745f771b

+ 3 - 0
Makefile.am

@@ -662,6 +662,7 @@ php_EXTRA_DIST=                                                       \
   php/tests/gdb_test.sh                                               \
   php/tests/generated_class_test.php                                  \
   php/tests/generated_phpdoc_test.php                                 \
+  php/tests/generated_service_test.php                                \
   php/tests/map_field_test.php                                        \
   php/tests/memory_leak_test.php                                      \
   php/tests/php_implementation_test.php                               \
@@ -672,6 +673,8 @@ php_EXTRA_DIST=                                                       \
   php/tests/proto/test_no_namespace.proto                             \
   php/tests/proto/test_php_namespace.proto                            \
   php/tests/proto/test_prefix.proto                                   \
+  php/tests/proto/test_service.proto                                  \
+  php/tests/proto/test_service_namespace.proto                        \
   php/tests/test.sh                                                   \
   php/tests/test_base.php                                             \
   php/tests/test_util.php                                             \

+ 89 - 60
csharp/src/Google.Protobuf/Reflection/Descriptor.cs

@@ -80,7 +80,7 @@ namespace Google.Protobuf.Reflection {
             "ASgJEhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5n",
             "b29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFt",
             "aW5nGAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVm",
-            "YWxzZSLLBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwK",
+            "YWxzZSLwBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwK",
             "FGphdmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVf",
             "ZmlsZXMYCiABKAg6BWZhbHNlEikKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2Fu",
             "ZF9oYXNoGBQgASgIQgIYARIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg",
@@ -88,65 +88,66 @@ namespace Google.Protobuf.Reflection {
             "dG9idWYuRmlsZU9wdGlvbnMuT3B0aW1pemVNb2RlOgVTUEVFRBISCgpnb19w",
             "YWNrYWdlGAsgASgJEiIKE2NjX2dlbmVyaWNfc2VydmljZXMYECABKAg6BWZh",
             "bHNlEiQKFWphdmFfZ2VuZXJpY19zZXJ2aWNlcxgRIAEoCDoFZmFsc2USIgoT",
-            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl",
-            "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs",
-            "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz",
-            "cGFjZRglIAEoCRIUCgxzd2lmdF9wcmVmaXgYJyABKAkSGAoQcGhwX2NsYXNz",
-            "X3ByZWZpeBgoIAEoCRIVCg1waHBfbmFtZXNwYWNlGCkgASgJEkMKFHVuaW50",
-            "ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5Vbmlu",
-            "dGVycHJldGVkT3B0aW9uIjoKDE9wdGltaXplTW9kZRIJCgVTUEVFRBABEg0K",
-            "CUNPREVfU0laRRACEhAKDExJVEVfUlVOVElNRRADKgkI6AcQgICAgAJKBAgm",
-            "ECci8gEKDk1lc3NhZ2VPcHRpb25zEiYKF21lc3NhZ2Vfc2V0X3dpcmVfZm9y",
-            "bWF0GAEgASgIOgVmYWxzZRIuCh9ub19zdGFuZGFyZF9kZXNjcmlwdG9yX2Fj",
-            "Y2Vzc29yGAIgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVmYWxz",
-            "ZRIRCgltYXBfZW50cnkYByABKAgSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y",
-            "5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24q",
-            "CQjoBxCAgICAAkoECAgQCUoECAkQCiKeAwoMRmllbGRPcHRpb25zEjoKBWN0",
-            "eXBlGAEgASgOMiMuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5DVHlw",
-            "ZToGU1RSSU5HEg4KBnBhY2tlZBgCIAEoCBI/CgZqc3R5cGUYBiABKA4yJC5n",
-            "b29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zLkpTVHlwZToJSlNfTk9STUFM",
-            "EhMKBGxhenkYBSABKAg6BWZhbHNlEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZh",
-            "bHNlEhMKBHdlYWsYCiABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0",
-            "aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0",
-            "aW9uIi8KBUNUeXBlEgoKBlNUUklORxAAEggKBENPUkQQARIQCgxTVFJJTkdf",
-            "UElFQ0UQAiI1CgZKU1R5cGUSDQoJSlNfTk9STUFMEAASDQoJSlNfU1RSSU5H",
-            "EAESDQoJSlNfTlVNQkVSEAIqCQjoBxCAgICAAkoECAQQBSJeCgxPbmVvZk9w",
-            "dGlvbnMSQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xl",
-            "LnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKTAQoL",
-            "RW51bU9wdGlvbnMSEwoLYWxsb3dfYWxpYXMYAiABKAgSGQoKZGVwcmVjYXRl",
-            "ZBgDIAEoCDoFZmFsc2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygL",
-            "MiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCA",
-            "gICAAkoECAUQBiJ9ChBFbnVtVmFsdWVPcHRpb25zEhkKCmRlcHJlY2F0ZWQY",
-            "ASABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIk",
+            "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USIwoUcGhwX2dlbmVy",
+            "aWNfc2VydmljZXMYEyABKAg6BWZhbHNlEhkKCmRlcHJlY2F0ZWQYFyABKAg6",
+            "BWZhbHNlEh8KEGNjX2VuYWJsZV9hcmVuYXMYHyABKAg6BWZhbHNlEhkKEW9i",
+            "amNfY2xhc3NfcHJlZml4GCQgASgJEhgKEGNzaGFycF9uYW1lc3BhY2UYJSAB",
+            "KAkSFAoMc3dpZnRfcHJlZml4GCcgASgJEhgKEHBocF9jbGFzc19wcmVmaXgY",
+            "KCABKAkSFQoNcGhwX25hbWVzcGFjZRgpIAEoCRJDChR1bmludGVycHJldGVk",
+            "X29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRl",
+            "ZE9wdGlvbiI6CgxPcHRpbWl6ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJ",
+            "WkUQAhIQCgxMSVRFX1JVTlRJTUUQAyoJCOgHEICAgIACSgQIJhAnIvIBCg5N",
+            "ZXNzYWdlT3B0aW9ucxImChdtZXNzYWdlX3NldF93aXJlX2Zvcm1hdBgBIAEo",
+            "CDoFZmFsc2USLgofbm9fc3RhbmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgC",
+            "IAEoCDoFZmFsc2USGQoKZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2USEQoJbWFw",
+            "X2VudHJ5GAcgASgIEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIk",
             "Lmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICA",
-            "gAIiewoOU2VydmljZU9wdGlvbnMSGQoKZGVwcmVjYXRlZBghIAEoCDoFZmFs",
-            "c2USQwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnBy",
-            "b3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKtAgoNTWV0",
-            "aG9kT3B0aW9ucxIZCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJfChFpZGVt",
-            "cG90ZW5jeV9sZXZlbBgiIAEoDjIvLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RP",
-            "cHRpb25zLklkZW1wb3RlbmN5TGV2ZWw6E0lERU1QT1RFTkNZX1VOS05PV04S",
-            "QwoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3Rv",
-            "YnVmLlVuaW50ZXJwcmV0ZWRPcHRpb24iUAoQSWRlbXBvdGVuY3lMZXZlbBIX",
-            "ChNJREVNUE9URU5DWV9VTktOT1dOEAASEwoPTk9fU0lERV9FRkZFQ1RTEAES",
-            "DgoKSURFTVBPVEVOVBACKgkI6AcQgICAgAIingIKE1VuaW50ZXJwcmV0ZWRP",
-            "cHRpb24SOwoEbmFtZRgCIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5VbmludGVy",
-            "cHJldGVkT3B0aW9uLk5hbWVQYXJ0EhgKEGlkZW50aWZpZXJfdmFsdWUYAyAB",
-            "KAkSGgoScG9zaXRpdmVfaW50X3ZhbHVlGAQgASgEEhoKEm5lZ2F0aXZlX2lu",
-            "dF92YWx1ZRgFIAEoAxIUCgxkb3VibGVfdmFsdWUYBiABKAESFAoMc3RyaW5n",
-            "X3ZhbHVlGAcgASgMEhcKD2FnZ3JlZ2F0ZV92YWx1ZRgIIAEoCRozCghOYW1l",
-            "UGFydBIRCgluYW1lX3BhcnQYASACKAkSFAoMaXNfZXh0ZW5zaW9uGAIgAigI",
-            "ItUBCg5Tb3VyY2VDb2RlSW5mbxI6Cghsb2NhdGlvbhgBIAMoCzIoLmdvb2ds",
-            "ZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5mby5Mb2NhdGlvbhqGAQoITG9jYXRp",
-            "b24SEAoEcGF0aBgBIAMoBUICEAESEAoEc3BhbhgCIAMoBUICEAESGAoQbGVh",
-            "ZGluZ19jb21tZW50cxgDIAEoCRIZChF0cmFpbGluZ19jb21tZW50cxgEIAEo",
-            "CRIhChlsZWFkaW5nX2RldGFjaGVkX2NvbW1lbnRzGAYgAygJIqcBChFHZW5l",
-            "cmF0ZWRDb2RlSW5mbxJBCgphbm5vdGF0aW9uGAEgAygLMi0uZ29vZ2xlLnBy",
-            "b3RvYnVmLkdlbmVyYXRlZENvZGVJbmZvLkFubm90YXRpb24aTwoKQW5ub3Rh",
-            "dGlvbhIQCgRwYXRoGAEgAygFQgIQARITCgtzb3VyY2VfZmlsZRgCIAEoCRIN",
-            "CgViZWdpbhgDIAEoBRILCgNlbmQYBCABKAVCjAEKE2NvbS5nb29nbGUucHJv",
-            "dG9idWZCEERlc2NyaXB0b3JQcm90b3NIAVo+Z2l0aHViLmNvbS9nb2xhbmcv",
-            "cHJvdG9idWYvcHJvdG9jLWdlbi1nby9kZXNjcmlwdG9yO2Rlc2NyaXB0b3Ki",
-            "AgNHUEKqAhpHb29nbGUuUHJvdG9idWYuUmVmbGVjdGlvbg=="));
+            "gAJKBAgIEAlKBAgJEAoingMKDEZpZWxkT3B0aW9ucxI6CgVjdHlwZRgBIAEo",
+            "DjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuQ1R5cGU6BlNUUklO",
+            "RxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYgASgOMiQuZ29vZ2xlLnBy",
+            "b3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpTX05PUk1BTBITCgRsYXp5",
+            "GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZRITCgR3",
+            "ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByAD",
+            "KAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiIvCgVD",
+            "VHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5HX1BJRUNFEAIi",
+            "NQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklORxABEg0KCUpT",
+            "X05VTUJFUhACKgkI6AcQgICAgAJKBAgEEAUiXgoMT25lb2ZPcHRpb25zEkMK",
+            "FHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1",
+            "Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIikwEKC0VudW1PcHRp",
+            "b25zEhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6",
+            "BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2ds",
+            "ZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgF",
+            "EAYifQoQRW51bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVm",
+            "YWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUu",
+            "cHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNl",
+            "cnZpY2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVu",
+            "aW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5V",
+            "bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIirQIKDU1ldGhvZE9wdGlv",
+            "bnMSGQoKZGVwcmVjYXRlZBghIAEoCDoFZmFsc2USXwoRaWRlbXBvdGVuY3lf",
+            "bGV2ZWwYIiABKA4yLy5nb29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucy5J",
+            "ZGVtcG90ZW5jeUxldmVsOhNJREVNUE9URU5DWV9VTktOT1dOEkMKFHVuaW50",
+            "ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5Vbmlu",
+            "dGVycHJldGVkT3B0aW9uIlAKEElkZW1wb3RlbmN5TGV2ZWwSFwoTSURFTVBP",
+            "VEVOQ1lfVU5LTk9XThAAEhMKD05PX1NJREVfRUZGRUNUUxABEg4KCklERU1Q",
+            "T1RFTlQQAioJCOgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsK",
+            "BG5hbWUYAiADKAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w",
+            "dGlvbi5OYW1lUGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBv",
+            "c2l0aXZlX2ludF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUY",
+            "BSABKAMSFAoMZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgH",
+            "IAEoDBIXCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJ",
+            "bmFtZV9wYXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291",
+            "cmNlQ29kZUluZm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9i",
+            "dWYuU291cmNlQ29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBh",
+            "dGgYASADKAVCAhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29t",
+            "bWVudHMYAyABKAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVh",
+            "ZGluZ19kZXRhY2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29k",
+            "ZUluZm8SQQoKYW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5H",
+            "ZW5lcmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoE",
+            "cGF0aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4Y",
+            "AyABKAUSCwoDZW5kGAQgASgFQowBChNjb20uZ29vZ2xlLnByb3RvYnVmQhBE",
+            "ZXNjcmlwdG9yUHJvdG9zSAFaPmdpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVm",
+            "L3Byb3RvYy1nZW4tZ28vZGVzY3JpcHRvcjtkZXNjcmlwdG9yogIDR1BCqgIa",
+            "R29vZ2xlLlByb3RvYnVmLlJlZmxlY3Rpb24="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
@@ -160,7 +161,7 @@ namespace Google.Protobuf.Reflection {
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueDescriptorProto), global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceDescriptorProto), global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser, new[]{ "Name", "Method", "Options" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodDescriptorProto), global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser, new[]{ "Name", "InputType", "OutputType", "Options", "ClientStreaming", "ServerStreaming" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "SwiftPrefix", "PhpClassPrefix", "PhpNamespace", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "PhpGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "SwiftPrefix", "PhpClassPrefix", "PhpNamespace", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MessageOptions), global::Google.Protobuf.Reflection.MessageOptions.Parser, new[]{ "MessageSetWireFormat", "NoStandardDescriptorAccessor", "Deprecated", "MapEntry", "UninterpretedOption" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), global::Google.Protobuf.Reflection.FieldOptions.Parser, new[]{ "Ctype", "Packed", "Jstype", "Lazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.OneofOptions), global::Google.Protobuf.Reflection.OneofOptions.Parser, new[]{ "UninterpretedOption" }, null, null, null),
@@ -2804,6 +2805,7 @@ namespace Google.Protobuf.Reflection {
       ccGenericServices_ = other.ccGenericServices_;
       javaGenericServices_ = other.javaGenericServices_;
       pyGenericServices_ = other.pyGenericServices_;
+      phpGenericServices_ = other.phpGenericServices_;
       deprecated_ = other.deprecated_;
       ccEnableArenas_ = other.ccEnableArenas_;
       objcClassPrefix_ = other.objcClassPrefix_;
@@ -2981,6 +2983,17 @@ namespace Google.Protobuf.Reflection {
       }
     }
 
+    /// <summary>Field number for the "php_generic_services" field.</summary>
+    public const int PhpGenericServicesFieldNumber = 19;
+    private bool phpGenericServices_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool PhpGenericServices {
+      get { return phpGenericServices_; }
+      set {
+        phpGenericServices_ = value;
+      }
+    }
+
     /// <summary>Field number for the "deprecated" field.</summary>
     public const int DeprecatedFieldNumber = 23;
     private bool deprecated_;
@@ -3126,6 +3139,7 @@ namespace Google.Protobuf.Reflection {
       if (CcGenericServices != other.CcGenericServices) return false;
       if (JavaGenericServices != other.JavaGenericServices) return false;
       if (PyGenericServices != other.PyGenericServices) return false;
+      if (PhpGenericServices != other.PhpGenericServices) return false;
       if (Deprecated != other.Deprecated) return false;
       if (CcEnableArenas != other.CcEnableArenas) return false;
       if (ObjcClassPrefix != other.ObjcClassPrefix) return false;
@@ -3150,6 +3164,7 @@ namespace Google.Protobuf.Reflection {
       if (CcGenericServices != false) hash ^= CcGenericServices.GetHashCode();
       if (JavaGenericServices != false) hash ^= JavaGenericServices.GetHashCode();
       if (PyGenericServices != false) hash ^= PyGenericServices.GetHashCode();
+      if (PhpGenericServices != false) hash ^= PhpGenericServices.GetHashCode();
       if (Deprecated != false) hash ^= Deprecated.GetHashCode();
       if (CcEnableArenas != false) hash ^= CcEnableArenas.GetHashCode();
       if (ObjcClassPrefix.Length != 0) hash ^= ObjcClassPrefix.GetHashCode();
@@ -3200,6 +3215,10 @@ namespace Google.Protobuf.Reflection {
         output.WriteRawTag(144, 1);
         output.WriteBool(PyGenericServices);
       }
+      if (PhpGenericServices != false) {
+        output.WriteRawTag(152, 1);
+        output.WriteBool(PhpGenericServices);
+      }
       if (JavaGenerateEqualsAndHash != false) {
         output.WriteRawTag(160, 1);
         output.WriteBool(JavaGenerateEqualsAndHash);
@@ -3272,6 +3291,9 @@ namespace Google.Protobuf.Reflection {
       if (PyGenericServices != false) {
         size += 2 + 1;
       }
+      if (PhpGenericServices != false) {
+        size += 2 + 1;
+      }
       if (Deprecated != false) {
         size += 2 + 1;
       }
@@ -3332,6 +3354,9 @@ namespace Google.Protobuf.Reflection {
       if (other.PyGenericServices != false) {
         PyGenericServices = other.PyGenericServices;
       }
+      if (other.PhpGenericServices != false) {
+        PhpGenericServices = other.PhpGenericServices;
+      }
       if (other.Deprecated != false) {
         Deprecated = other.Deprecated;
       }
@@ -3396,6 +3421,10 @@ namespace Google.Protobuf.Reflection {
             PyGenericServices = input.ReadBool();
             break;
           }
+          case 152: {
+            PhpGenericServices = input.ReadBool();
+            break;
+          }
           case 160: {
             JavaGenerateEqualsAndHash = input.ReadBool();
             break;

+ 1 - 0
php/phpunit.xml

@@ -10,6 +10,7 @@
       <file>tests/generated_phpdoc_test.php</file>
       <file>tests/map_field_test.php</file>
       <file>tests/well_known_test.php</file>
+      <file>tests/generated_service_test.php</file>
     </testsuite>
   </testsuites>
 </phpunit>

+ 1 - 0
php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php

@@ -139,6 +139,7 @@ class Descriptor
             ->optional('cc_generic_services', \Google\Protobuf\Internal\GPBType::BOOL, 16)
             ->optional('java_generic_services', \Google\Protobuf\Internal\GPBType::BOOL, 17)
             ->optional('py_generic_services', \Google\Protobuf\Internal\GPBType::BOOL, 18)
+            ->optional('php_generic_services', \Google\Protobuf\Internal\GPBType::BOOL, 19)
             ->optional('deprecated', \Google\Protobuf\Internal\GPBType::BOOL, 23)
             ->optional('cc_enable_arenas', \Google\Protobuf\Internal\GPBType::BOOL, 31)
             ->optional('objc_class_prefix', \Google\Protobuf\Internal\GPBType::STRING, 36)

+ 33 - 0
php/src/Google/Protobuf/Internal/FileOptions.php

@@ -109,6 +109,11 @@ class FileOptions extends \Google\Protobuf\Internal\Message
      */
     private $py_generic_services = false;
     private $has_py_generic_services = false;
+    /**
+     * Generated from protobuf field <code>optional bool php_generic_services = 19 [default = false];</code>
+     */
+    private $php_generic_services = false;
+    private $has_php_generic_services = false;
     /**
      * Is this file deprecated?
      * Depending on the target platform, this can emit Deprecated annotations
@@ -548,6 +553,34 @@ class FileOptions extends \Google\Protobuf\Internal\Message
         return $this->has_py_generic_services;
     }
 
+    /**
+     * Generated from protobuf field <code>optional bool php_generic_services = 19 [default = false];</code>
+     * @return bool
+     */
+    public function getPhpGenericServices()
+    {
+        return $this->php_generic_services;
+    }
+
+    /**
+     * Generated from protobuf field <code>optional bool php_generic_services = 19 [default = false];</code>
+     * @param bool $var
+     * @return $this
+     */
+    public function setPhpGenericServices($var)
+    {
+        GPBUtil::checkBool($var);
+        $this->php_generic_services = $var;
+        $this->has_php_generic_services = true;
+
+        return $this;
+    }
+
+    public function hasPhpGenericServices()
+    {
+        return $this->has_php_generic_services;
+    }
+
     /**
      * Is this file deprecated?
      * Depending on the target platform, this can emit Deprecated annotations

+ 110 - 0
php/tests/generated_service_test.php

@@ -0,0 +1,110 @@
+<?php
+
+require_once('test_base.php');
+require_once('test_util.php');
+
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\MapField;
+use Google\Protobuf\Internal\GPBType;
+use Foo\Greeter;
+use Foo\HelloRequest;
+use Foo\HelloReply;
+
+class GeneratedServiceTest extends TestBase
+{
+    /**
+     * @var \ReflectionClass
+     */
+    private $serviceClass;
+
+    /**
+     * @var \ReflectionClass
+     */
+    private $namespacedServiceClass;
+
+    /**
+     * @var array
+     */
+    private $methodNames = [
+        'sayHello',
+        'sayHelloAgain'
+    ];
+
+    public function setUp()
+    {
+        parent::setUp();
+
+        $this->serviceClass = new ReflectionClass('Foo\GreeterInterface');
+
+        $this->namespacedServiceClass = new ReflectionClass('Bar\OtherGreeterInterface');
+    }
+
+    public function testIsInterface()
+    {
+        $this->assertTrue($this->serviceClass->isInterface());
+    }
+
+    public function testPhpDocForClass()
+    {
+        $this->assertContains('foo.Greeter', $this->serviceClass->getDocComment());
+    }
+
+    public function testPhpDocForNamespacedClass()
+    {
+        $this->assertContains('foo.OtherGreeter', $this->namespacedServiceClass->getDocComment());
+    }
+
+    public function testServiceMethodsAreGenerated()
+    {
+        $this->assertCount(count($this->methodNames), $this->serviceClass->getMethods());
+        foreach ($this->methodNames as $methodName) {
+            $this->assertTrue($this->serviceClass->hasMethod($methodName));
+        }
+    }
+
+    public function testPhpDocForServiceMethod()
+    {
+        foreach ($this->methodNames as $methodName) {
+            $docComment = $this->serviceClass->getMethod($methodName)->getDocComment();
+            $this->assertContains($methodName, $docComment);
+            $this->assertContains('@param \Foo\HelloRequest $request', $docComment);
+            $this->assertContains('@return \Foo\HelloReply', $docComment);
+        }
+    }
+
+    public function testPhpDocForServiceMethodInNamespacedClass()
+    {
+        foreach ($this->methodNames as $methodName) {
+            $docComment = $this->namespacedServiceClass->getMethod($methodName)->getDocComment();
+            $this->assertContains($methodName, $docComment);
+            $this->assertContains('@param \Foo\HelloRequest $request', $docComment);
+            $this->assertContains('@return \Foo\HelloReply', $docComment);
+        }
+    }
+
+    public function testParamForServiceMethod()
+    {
+        foreach ($this->methodNames as $methodName) {
+            $method = $this->serviceClass->getMethod($methodName);
+            $this->assertCount(1, $method->getParameters());
+            $param = $method->getParameters()[0];
+            $this->assertFalse($param->isOptional());
+            $this->assertSame('request', $param->getName());
+            // ReflectionParameter::getType only exists in PHP 7+, so get the type from __toString
+            $this->assertContains('Foo\HelloRequest $request', (string) $param);
+        }
+    }
+
+    public function testParamForServiceMethodInNamespacedClass()
+    {
+        foreach ($this->methodNames as $methodName) {
+            $method = $this->serviceClass->getMethod($methodName);
+            $this->assertCount(1, $method->getParameters());
+            $param = $method->getParameters()[0];
+            $this->assertFalse($param->isOptional());
+            $this->assertSame('request', $param->getName());
+            // ReflectionParameter::getType only exists in PHP 7+, so get the type from __toString
+            $this->assertContains('Foo\HelloRequest $request', (string) $param);
+        }
+    }
+}

+ 18 - 0
php/tests/proto/test_service.proto

@@ -0,0 +1,18 @@
+syntax = "proto3";
+
+package foo;
+
+option php_generic_services = true;
+
+service Greeter {
+  rpc SayHello (HelloRequest) returns (HelloReply) {}
+  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
+}
+
+message HelloRequest {
+  string name = 1;
+}
+
+message HelloReply {
+  string message = 1;
+}

+ 13 - 0
php/tests/proto/test_service_namespace.proto

@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+import "proto/test_service.proto";
+
+package foo;
+
+option php_generic_services = true;
+option php_namespace = "Bar";
+
+service OtherGreeter {
+  rpc SayHello (HelloRequest) returns (HelloReply) {}
+  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
+}

+ 1 - 1
php/tests/test.sh

@@ -8,7 +8,7 @@ set -e
 phpize && ./configure CFLAGS='-g -O0' && make
 popd
 
-tests=( array_test.php encode_decode_test.php generated_class_test.php generated_phpdoc_test.php map_field_test.php well_known_test.php )
+tests=( array_test.php encode_decode_test.php generated_class_test.php generated_phpdoc_test.php map_field_test.php well_known_test.php generated_service_test.php )
 
 for t in "${tests[@]}"
 do

+ 130 - 10
src/google/protobuf/compiler/php/php_generator.cc

@@ -82,6 +82,10 @@ void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
                             int is_descriptor);
 void GenerateEnumValueDocComment(io::Printer* printer,
                                  const EnumValueDescriptor* value);
+void GenerateServiceDocComment(io::Printer* printer,
+                               const ServiceDescriptor* service);
+void GenerateServiceMethodDocComment(io::Printer* printer,
+                              const MethodDescriptor* method);
 
 std::string RenameEmpty(const std::string& name) {
   if (name == "Empty") {
@@ -139,17 +143,9 @@ std::string ClassNamePrefix(const string& classname,
   return "";
 }
 
-
 template <typename DescriptorType>
-std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
-  string classname = desc->name();
-  const Descriptor* containing = desc->containing_type();
-  while (containing != NULL) {
-    classname = containing->name() + '_' + classname;
-    containing = containing->containing_type();
-  }
-  classname = ClassNamePrefix(classname, desc) + classname;
-
+std::string NamespacedName(const string& classname,
+                            const DescriptorType* desc, bool is_descriptor) {
   if (desc->file()->options().has_php_namespace()) {
     const string& php_namespace = desc->file()->options().php_namespace();
     if (php_namespace != "") {
@@ -167,6 +163,24 @@ std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
   }
 }
 
+template <typename DescriptorType>
+std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
+  string classname = desc->name();
+  const Descriptor* containing = desc->containing_type();
+  while (containing != NULL) {
+    classname = containing->name() + '_' + classname;
+    containing = containing->containing_type();
+  }
+  classname = ClassNamePrefix(classname, desc) + classname;
+  return NamespacedName(classname, desc, is_descriptor);
+}
+
+std::string FullClassName(const ServiceDescriptor* desc, bool is_descriptor) {
+  string classname = desc->name();
+  classname = ClassNamePrefix(classname, desc) + classname;
+  return NamespacedName(classname, desc, is_descriptor);
+}
+
 std::string PhpName(const std::string& full_name, bool is_descriptor) {
   if (is_descriptor) {
     return kDescriptorPackageName;
@@ -272,6 +286,17 @@ std::string GeneratedEnumFileName(const EnumDescriptor* en,
   return result + ".php";
 }
 
+std::string GeneratedServiceFileName(const ServiceDescriptor* service,
+                                    bool is_descriptor) {
+  std::string result = FullClassName(service, is_descriptor) + "Interface";
+  for (int i = 0; i < result.size(); i++) {
+    if (result[i] == '\\') {
+      result[i] = '/';
+    }
+  }
+  return result + ".php";
+}
+
 std::string IntToString(int32 value) {
   std::ostringstream os;
   os << value;
@@ -660,6 +685,16 @@ void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) {
   Outdent(printer);
 }
 
+void GenerateServiceMethod(const MethodDescriptor* method,
+                           io::Printer* printer) {
+  printer->Print(
+        "public function ^camel_name^(\\^request_name^ $request);\n\n",
+        "camel_name", UnderscoresToCamelCase(method->name(), false),
+        "request_name", FullClassName(
+          method->input_type(), false)
+  );
+}
+
 void GenerateMessageToPool(const string& name_prefix, const Descriptor* message,
                            io::Printer* printer) {
   // Don't generate MapEntry messages -- we use the PHP extension's native
@@ -1061,6 +1096,58 @@ void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
   }
 }
 
+void GenerateServiceFile(const FileDescriptor* file,
+  const ServiceDescriptor* service, bool is_descriptor,
+  GeneratorContext* generator_context) {
+  std::string filename = GeneratedServiceFileName(service, is_descriptor);
+  scoped_ptr<io::ZeroCopyOutputStream> output(
+      generator_context->Open(filename));
+  io::Printer printer(output.get(), '^');
+
+  GenerateHead(file, &printer);
+
+  std::string fullname = FilenameToClassname(filename);
+  int lastindex = fullname.find_last_of("\\");
+
+  if (file->options().has_php_namespace()) {
+    const string& php_namespace = file->options().php_namespace();
+    if (!php_namespace.empty()) {
+      printer.Print(
+          "namespace ^name^;\n\n",
+          "name", php_namespace);
+    }
+  } else if (!file->package().empty()) {
+    printer.Print(
+        "namespace ^name^;\n\n",
+        "name", fullname.substr(0, lastindex));
+  }
+
+  GenerateServiceDocComment(&printer, service);
+
+  if (lastindex != string::npos) {
+      printer.Print(
+        "interface ^name^\n"
+        "{\n",
+        "name", fullname.substr(lastindex + 1));
+  } else {
+      printer.Print(
+        "interface ^name^\n"
+        "{\n",
+        "name", fullname);
+  }
+
+  Indent(&printer);
+
+  for (int i = 0; i < service->method_count(); i++) {
+    const MethodDescriptor* method = service->method(i);
+    GenerateServiceMethodDocComment(&printer, method);
+    GenerateServiceMethod(method, &printer);
+  }
+
+  Outdent(&printer);
+  printer.Print("}\n\n");
+}
+
 void GenerateFile(const FileDescriptor* file, bool is_descriptor,
                   GeneratorContext* generator_context) {
   GenerateMetadataFile(file, is_descriptor, generator_context);
@@ -1072,6 +1159,12 @@ void GenerateFile(const FileDescriptor* file, bool is_descriptor,
     GenerateEnumFile(file, file->enum_type(i), is_descriptor,
                      generator_context);
   }
+  if (file->options().php_generic_services()) {
+    for (int i = 0; i < file->service_count(); i++) {
+      GenerateServiceFile(file, file->service(i), is_descriptor,
+                       generator_context);
+    }
+  }
 }
 
 static string EscapePhpdoc(const string& input) {
@@ -1180,6 +1273,16 @@ void GenerateMessageDocComment(io::Printer* printer,
     "messagename", EscapePhpdoc(message->full_name()));
 }
 
+void GenerateServiceDocComment(io::Printer* printer,
+                               const ServiceDescriptor* service) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, service);
+  printer->Print(
+    " * Protobuf type <code>^fullname^</code>\n"
+    " */\n",
+    "fullname", EscapePhpdoc(service->full_name()));
+}
+
 void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
                              int is_descriptor, int function_type) {
   // In theory we should have slightly different comments for setters, getters,
@@ -1226,6 +1329,23 @@ void GenerateEnumValueDocComment(io::Printer* printer,
     "def", EscapePhpdoc(FirstLineOf(value->DebugString())));
 }
 
+void GenerateServiceMethodDocComment(io::Printer* printer,
+                              const MethodDescriptor* method) {
+  printer->Print("/**\n");
+  GenerateDocCommentBody(printer, method);
+  printer->Print(
+    " * Method <code>^method_name^</code>\n"
+    " *\n",
+    "method_name", EscapePhpdoc(UnderscoresToCamelCase(method->name(), false)));
+  printer->Print(
+    " * @param \\^input_type^ $request\n",
+    "input_type", EscapePhpdoc(FullClassName(method->input_type(), false)));
+  printer->Print(
+    " * @return \\^return_type^\n"
+    " */\n",
+    "return_type", EscapePhpdoc(FullClassName(method->output_type(), false)));
+}
+
 bool Generator::Generate(const FileDescriptor* file, const string& parameter,
                          GeneratorContext* generator_context,
                          string* error) const {

+ 179 - 110
src/google/protobuf/descriptor.pb.cc

@@ -297,6 +297,7 @@ const ::google::protobuf::uint32 TableStruct::offsets[] = {
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, php_generic_services_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, deprecated_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_enable_arenas_),
   GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, objc_class_prefix_),
@@ -310,13 +311,14 @@ const ::google::protobuf::uint32 TableStruct::offsets[] = {
   8,
   9,
   10,
-  16,
+  17,
   2,
   11,
   12,
   13,
   14,
   15,
+  16,
   3,
   4,
   5,
@@ -488,20 +490,20 @@ static const ::google::protobuf::internal::MigrationSchema schemas[] = {
   { 124, 132, sizeof(EnumValueDescriptorProto)},
   { 135, 143, sizeof(ServiceDescriptorProto)},
   { 146, 157, sizeof(MethodDescriptorProto)},
-  { 163, 186, sizeof(FileOptions)},
-  { 204, 214, sizeof(MessageOptions)},
-  { 219, 231, sizeof(FieldOptions)},
-  { 238, 244, sizeof(OneofOptions)},
-  { 245, 253, sizeof(EnumOptions)},
-  { 256, 263, sizeof(EnumValueOptions)},
-  { 265, 272, sizeof(ServiceOptions)},
-  { 274, 282, sizeof(MethodOptions)},
-  { 285, 292, sizeof(UninterpretedOption_NamePart)},
-  { 294, 306, sizeof(UninterpretedOption)},
-  { 313, 323, sizeof(SourceCodeInfo_Location)},
-  { 328, 334, sizeof(SourceCodeInfo)},
-  { 335, 344, sizeof(GeneratedCodeInfo_Annotation)},
-  { 348, 354, sizeof(GeneratedCodeInfo)},
+  { 163, 187, sizeof(FileOptions)},
+  { 206, 216, sizeof(MessageOptions)},
+  { 221, 233, sizeof(FieldOptions)},
+  { 240, 246, sizeof(OneofOptions)},
+  { 247, 255, sizeof(EnumOptions)},
+  { 258, 265, sizeof(EnumValueOptions)},
+  { 267, 274, sizeof(ServiceOptions)},
+  { 276, 284, sizeof(MethodOptions)},
+  { 287, 294, sizeof(UninterpretedOption_NamePart)},
+  { 296, 308, sizeof(UninterpretedOption)},
+  { 315, 325, sizeof(SourceCodeInfo_Location)},
+  { 330, 336, sizeof(SourceCodeInfo)},
+  { 337, 346, sizeof(GeneratedCodeInfo_Annotation)},
+  { 350, 356, sizeof(GeneratedCodeInfo)},
 };
 
 static ::google::protobuf::Message const * const file_default_instances[] = {
@@ -729,7 +731,7 @@ void AddDescriptorsImpl() {
       "\n\013output_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.g"
       "oogle.protobuf.MethodOptions\022\037\n\020client_s"
       "treaming\030\005 \001(\010:\005false\022\037\n\020server_streamin"
-      "g\030\006 \001(\010:\005false\"\313\005\n\013FileOptions\022\024\n\014java_p"
+      "g\030\006 \001(\010:\005false\"\360\005\n\013FileOptions\022\024\n\014java_p"
       "ackage\030\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001"
       "(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005false\022)"
       "\n\035java_generate_equals_and_hash\030\024 \001(\010B\002\030"
@@ -739,75 +741,76 @@ void AddDescriptorsImpl() {
       "ackage\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001("
       "\010:\005false\022$\n\025java_generic_services\030\021 \001(\010:"
       "\005false\022\"\n\023py_generic_services\030\022 \001(\010:\005fal"
-      "se\022\031\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enab"
-      "le_arenas\030\037 \001(\010:\005false\022\031\n\021objc_class_pre"
-      "fix\030$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022\024\n\014s"
-      "wift_prefix\030\' \001(\t\022\030\n\020php_class_prefix\030( "
-      "\001(\t\022\025\n\rphp_namespace\030) \001(\t\022C\n\024uninterpre"
-      "ted_option\030\347\007 \003(\0132$.google.protobuf.Unin"
-      "terpretedOption\":\n\014OptimizeMode\022\t\n\005SPEED"
-      "\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007"
-      "\020\200\200\200\200\002J\004\010&\020\'\"\362\001\n\016MessageOptions\022&\n\027messa"
-      "ge_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_st"
-      "andard_descriptor_accessor\030\002 \001(\010:\005false\022"
-      "\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030"
-      "\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g"
-      "oogle.protobuf.UninterpretedOption*\t\010\350\007\020"
-      "\200\200\200\200\002J\004\010\010\020\tJ\004\010\t\020\n\"\236\003\n\014FieldOptions\022:\n\005ct"
-      "ype\030\001 \001(\0162#.google.protobuf.FieldOptions"
-      ".CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype"
-      "\030\006 \001(\0162$.google.protobuf.FieldOptions.JS"
-      "Type:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\n"
-      "deprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005f"
-      "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
-      "ogle.protobuf.UninterpretedOption\"/\n\005CTy"
-      "pe\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE"
-      "\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING"
-      "\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002J\004\010\004\020\005\"^\n\014On"
-      "eofOptions\022C\n\024uninterpreted_option\030\347\007 \003("
-      "\0132$.google.protobuf.UninterpretedOption*"
-      "\t\010\350\007\020\200\200\200\200\002\"\223\001\n\013EnumOptions\022\023\n\013allow_alia"
-      "s\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024un"
-      "interpreted_option\030\347\007 \003(\0132$.google.proto"
-      "buf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\005\020\006"
-      "\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010"
-      ":\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$"
+      "se\022#\n\024php_generic_services\030\023 \001(\010:\005false\022"
+      "\031\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_"
+      "arenas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix"
+      "\030$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022\024\n\014swif"
+      "t_prefix\030\' \001(\t\022\030\n\020php_class_prefix\030( \001(\t"
+      "\022\025\n\rphp_namespace\030) \001(\t\022C\n\024uninterpreted"
+      "_option\030\347\007 \003(\0132$.google.protobuf.Uninter"
+      "pretedOption\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022"
+      "\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200"
+      "\200\200\002J\004\010&\020\'\"\362\001\n\016MessageOptions\022&\n\027message_"
+      "set_wire_format\030\001 \001(\010:\005false\022.\n\037no_stand"
+      "ard_descriptor_accessor\030\002 \001(\010:\005false\022\031\n\n"
+      "deprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007 \001"
+      "(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goog"
+      "le.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200"
+      "\200\002J\004\010\010\020\tJ\004\010\t\020\n\"\236\003\n\014FieldOptions\022:\n\005ctype"
+      "\030\001 \001(\0162#.google.protobuf.FieldOptions.CT"
+      "ype:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 "
+      "\001(\0162$.google.protobuf.FieldOptions.JSTyp"
+      "e:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndep"
+      "recated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005fals"
+      "e\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.googl"
+      "e.protobuf.UninterpretedOption\"/\n\005CType\022"
+      "\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\""
+      "5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022"
+      "\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002J\004\010\004\020\005\"^\n\014Oneof"
+      "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$"
       ".google.protobuf.UninterpretedOption*\t\010\350"
-      "\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030"
-      "! \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 "
-      "\003(\0132$.google.protobuf.UninterpretedOptio"
-      "n*\t\010\350\007\020\200\200\200\200\002\"\255\002\n\rMethodOptions\022\031\n\ndeprec"
-      "ated\030! \001(\010:\005false\022_\n\021idempotency_level\030\""
-      " \001(\0162/.google.protobuf.MethodOptions.Ide"
-      "mpotencyLevel:\023IDEMPOTENCY_UNKNOWN\022C\n\024un"
-      "interpreted_option\030\347\007 \003(\0132$.google.proto"
-      "buf.UninterpretedOption\"P\n\020IdempotencyLe"
-      "vel\022\027\n\023IDEMPOTENCY_UNKNOWN\020\000\022\023\n\017NO_SIDE_"
-      "EFFECTS\020\001\022\016\n\nIDEMPOTENT\020\002*\t\010\350\007\020\200\200\200\200\002\"\236\002\n"
-      "\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goo"
-      "gle.protobuf.UninterpretedOption.NamePar"
-      "t\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_"
-      "int_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 "
-      "\001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_valu"
-      "e\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010Name"
-      "Part\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030"
-      "\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003"
-      "(\0132(.google.protobuf.SourceCodeInfo.Loca"
-      "tion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004s"
-      "pan\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022"
-      "\031\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_de"
-      "tached_comments\030\006 \003(\t\"\247\001\n\021GeneratedCodeI"
-      "nfo\022A\n\nannotation\030\001 \003(\0132-.google.protobu"
-      "f.GeneratedCodeInfo.Annotation\032O\n\nAnnota"
-      "tion\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source_file\030\002 "
-      "\001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B\214\001\n\023com."
-      "google.protobufB\020DescriptorProtosH\001Z>git"
-      "hub.com/golang/protobuf/protoc-gen-go/de"
-      "scriptor;descriptor\242\002\003GPB\252\002\032Google.Proto"
-      "buf.Reflection"
+      "\007\020\200\200\200\200\002\"\223\001\n\013EnumOptions\022\023\n\013allow_alias\030\002"
+      " \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024unint"
+      "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
+      ".UninterpretedOption*\t\010\350\007\020\200\200\200\200\002J\004\010\005\020\006\"}\n"
+      "\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:\005f"
+      "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
+      "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
+      "\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030! \001"
+      "(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(\013"
+      "2$.google.protobuf.UninterpretedOption*\t"
+      "\010\350\007\020\200\200\200\200\002\"\255\002\n\rMethodOptions\022\031\n\ndeprecate"
+      "d\030! \001(\010:\005false\022_\n\021idempotency_level\030\" \001("
+      "\0162/.google.protobuf.MethodOptions.Idempo"
+      "tencyLevel:\023IDEMPOTENCY_UNKNOWN\022C\n\024unint"
+      "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
+      ".UninterpretedOption\"P\n\020IdempotencyLevel"
+      "\022\027\n\023IDEMPOTENCY_UNKNOWN\020\000\022\023\n\017NO_SIDE_EFF"
+      "ECTS\020\001\022\016\n\nIDEMPOTENT\020\002*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023Un"
+      "interpretedOption\022;\n\004name\030\002 \003(\0132-.google"
+      ".protobuf.UninterpretedOption.NamePart\022\030"
+      "\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_int"
+      "_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001(\003"
+      "\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_value\030\007"
+      " \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010NamePar"
+      "t\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002 \002"
+      "(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003(\0132"
+      "(.google.protobuf.SourceCodeInfo.Locatio"
+      "n\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span"
+      "\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022\031\n\021"
+      "trailing_comments\030\004 \001(\t\022!\n\031leading_detac"
+      "hed_comments\030\006 \003(\t\"\247\001\n\021GeneratedCodeInfo"
+      "\022A\n\nannotation\030\001 \003(\0132-.google.protobuf.G"
+      "eneratedCodeInfo.Annotation\032O\n\nAnnotatio"
+      "n\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t"
+      "\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B\214\001\n\023com.goo"
+      "gle.protobufB\020DescriptorProtosH\001Z>github"
+      ".com/golang/protobuf/protoc-gen-go/descr"
+      "iptor;descriptor\242\002\003GPB\252\002\032Google.Protobuf"
+      ".Reflection"
   };
   ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
-      descriptor, 5614);
+      descriptor, 5651);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
   ::google::protobuf::internal::OnShutdown(&TableStruct::Shutdown);
@@ -8292,6 +8295,7 @@ const int FileOptions::kGoPackageFieldNumber;
 const int FileOptions::kCcGenericServicesFieldNumber;
 const int FileOptions::kJavaGenericServicesFieldNumber;
 const int FileOptions::kPyGenericServicesFieldNumber;
+const int FileOptions::kPhpGenericServicesFieldNumber;
 const int FileOptions::kDeprecatedFieldNumber;
 const int FileOptions::kCcEnableArenasFieldNumber;
 const int FileOptions::kObjcClassPrefixFieldNumber;
@@ -8451,10 +8455,13 @@ void FileOptions::Clear() {
   }
   if (_has_bits_[8 / 32] & 65280u) {
     ::memset(&java_multiple_files_, 0, static_cast<size_t>(
-        reinterpret_cast<char*>(&cc_enable_arenas_) -
-        reinterpret_cast<char*>(&java_multiple_files_)) + sizeof(cc_enable_arenas_));
+        reinterpret_cast<char*>(&deprecated_) -
+        reinterpret_cast<char*>(&java_multiple_files_)) + sizeof(deprecated_));
+  }
+  if (_has_bits_[16 / 32] & 196608u) {
+    cc_enable_arenas_ = false;
+    optimize_for_ = 1;
   }
-  optimize_for_ = 1;
   _has_bits_.Clear();
   _internal_metadata_.Clear();
 }
@@ -8593,6 +8600,20 @@ bool FileOptions::MergePartialFromCodedStream(
         break;
       }
 
+      // optional bool php_generic_services = 19 [default = false];
+      case 19: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(152u)) {
+          set_has_php_generic_services();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &php_generic_services_)));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
       // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
       case 20: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
@@ -8796,7 +8817,7 @@ void FileOptions::SerializeWithCachedSizes(
   }
 
   // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
-  if (cached_has_bits & 0x00010000u) {
+  if (cached_has_bits & 0x00020000u) {
     ::google::protobuf::internal::WireFormatLite::WriteEnum(
       9, this->optimize_for(), output);
   }
@@ -8831,13 +8852,18 @@ void FileOptions::SerializeWithCachedSizes(
     ::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output);
   }
 
+  // optional bool php_generic_services = 19 [default = false];
+  if (cached_has_bits & 0x00004000u) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(19, this->php_generic_services(), output);
+  }
+
   // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
   if (cached_has_bits & 0x00000200u) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(20, this->java_generate_equals_and_hash(), output);
   }
 
   // optional bool deprecated = 23 [default = false];
-  if (cached_has_bits & 0x00004000u) {
+  if (cached_has_bits & 0x00008000u) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(23, this->deprecated(), output);
   }
 
@@ -8847,7 +8873,7 @@ void FileOptions::SerializeWithCachedSizes(
   }
 
   // optional bool cc_enable_arenas = 31 [default = false];
-  if (cached_has_bits & 0x00008000u) {
+  if (cached_has_bits & 0x00010000u) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(31, this->cc_enable_arenas(), output);
   }
 
@@ -8949,7 +8975,7 @@ void FileOptions::SerializeWithCachedSizes(
   }
 
   // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
-  if (cached_has_bits & 0x00010000u) {
+  if (cached_has_bits & 0x00020000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
       9, this->optimize_for(), target);
   }
@@ -8985,13 +9011,18 @@ void FileOptions::SerializeWithCachedSizes(
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target);
   }
 
+  // optional bool php_generic_services = 19 [default = false];
+  if (cached_has_bits & 0x00004000u) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(19, this->php_generic_services(), target);
+  }
+
   // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
   if (cached_has_bits & 0x00000200u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(20, this->java_generate_equals_and_hash(), target);
   }
 
   // optional bool deprecated = 23 [default = false];
-  if (cached_has_bits & 0x00004000u) {
+  if (cached_has_bits & 0x00008000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(23, this->deprecated(), target);
   }
 
@@ -9001,7 +9032,7 @@ void FileOptions::SerializeWithCachedSizes(
   }
 
   // optional bool cc_enable_arenas = 31 [default = false];
-  if (cached_has_bits & 0x00008000u) {
+  if (cached_has_bits & 0x00010000u) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(31, this->cc_enable_arenas(), target);
   }
 
@@ -9191,23 +9222,30 @@ size_t FileOptions::ByteSizeLong() const {
       total_size += 2 + 1;
     }
 
+    // optional bool php_generic_services = 19 [default = false];
+    if (has_php_generic_services()) {
+      total_size += 2 + 1;
+    }
+
     // optional bool deprecated = 23 [default = false];
     if (has_deprecated()) {
       total_size += 2 + 1;
     }
 
+  }
+  if (_has_bits_[16 / 32] & 196608u) {
     // optional bool cc_enable_arenas = 31 [default = false];
     if (has_cc_enable_arenas()) {
       total_size += 2 + 1;
     }
 
-  }
-  // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
-  if (has_optimize_for()) {
-    total_size += 1 +
-      ::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for());
-  }
+    // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
+    if (has_optimize_for()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for());
+    }
 
+  }
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
   GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
   _cached_size_ = cached_size;
@@ -9294,15 +9332,21 @@ void FileOptions::MergeFrom(const FileOptions& from) {
       py_generic_services_ = from.py_generic_services_;
     }
     if (cached_has_bits & 0x00004000u) {
-      deprecated_ = from.deprecated_;
+      php_generic_services_ = from.php_generic_services_;
     }
     if (cached_has_bits & 0x00008000u) {
-      cc_enable_arenas_ = from.cc_enable_arenas_;
+      deprecated_ = from.deprecated_;
     }
     _has_bits_[0] |= cached_has_bits;
   }
-  if (cached_has_bits & 0x00010000u) {
-    set_optimize_for(from.optimize_for());
+  if (cached_has_bits & 196608u) {
+    if (cached_has_bits & 0x00010000u) {
+      cc_enable_arenas_ = from.cc_enable_arenas_;
+    }
+    if (cached_has_bits & 0x00020000u) {
+      optimize_for_ = from.optimize_for_;
+    }
+    _has_bits_[0] |= cached_has_bits;
   }
 }
 
@@ -9349,6 +9393,7 @@ void FileOptions::InternalSwap(FileOptions* other) {
   std::swap(cc_generic_services_, other->cc_generic_services_);
   std::swap(java_generic_services_, other->java_generic_services_);
   std::swap(py_generic_services_, other->py_generic_services_);
+  std::swap(php_generic_services_, other->php_generic_services_);
   std::swap(deprecated_, other->deprecated_);
   std::swap(cc_enable_arenas_, other->cc_enable_arenas_);
   std::swap(optimize_for_, other->optimize_for_);
@@ -9566,13 +9611,13 @@ void FileOptions::set_java_string_check_utf8(bool value) {
 
 // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
 bool FileOptions::has_optimize_for() const {
-  return (_has_bits_[0] & 0x00010000u) != 0;
+  return (_has_bits_[0] & 0x00020000u) != 0;
 }
 void FileOptions::set_has_optimize_for() {
-  _has_bits_[0] |= 0x00010000u;
+  _has_bits_[0] |= 0x00020000u;
 }
 void FileOptions::clear_has_optimize_for() {
-  _has_bits_[0] &= ~0x00010000u;
+  _has_bits_[0] &= ~0x00020000u;
 }
 void FileOptions::clear_optimize_for() {
   optimize_for_ = 1;
@@ -9724,15 +9769,39 @@ void FileOptions::set_py_generic_services(bool value) {
   // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
 }
 
+// optional bool php_generic_services = 19 [default = false];
+bool FileOptions::has_php_generic_services() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void FileOptions::set_has_php_generic_services() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void FileOptions::clear_has_php_generic_services() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void FileOptions::clear_php_generic_services() {
+  php_generic_services_ = false;
+  clear_has_php_generic_services();
+}
+bool FileOptions::php_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_generic_services)
+  return php_generic_services_;
+}
+void FileOptions::set_php_generic_services(bool value) {
+  set_has_php_generic_services();
+  php_generic_services_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_generic_services)
+}
+
 // optional bool deprecated = 23 [default = false];
 bool FileOptions::has_deprecated() const {
-  return (_has_bits_[0] & 0x00004000u) != 0;
+  return (_has_bits_[0] & 0x00008000u) != 0;
 }
 void FileOptions::set_has_deprecated() {
-  _has_bits_[0] |= 0x00004000u;
+  _has_bits_[0] |= 0x00008000u;
 }
 void FileOptions::clear_has_deprecated() {
-  _has_bits_[0] &= ~0x00004000u;
+  _has_bits_[0] &= ~0x00008000u;
 }
 void FileOptions::clear_deprecated() {
   deprecated_ = false;
@@ -9750,13 +9819,13 @@ void FileOptions::set_deprecated(bool value) {
 
 // optional bool cc_enable_arenas = 31 [default = false];
 bool FileOptions::has_cc_enable_arenas() const {
-  return (_has_bits_[0] & 0x00008000u) != 0;
+  return (_has_bits_[0] & 0x00010000u) != 0;
 }
 void FileOptions::set_has_cc_enable_arenas() {
-  _has_bits_[0] |= 0x00008000u;
+  _has_bits_[0] |= 0x00010000u;
 }
 void FileOptions::clear_has_cc_enable_arenas() {
-  _has_bits_[0] &= ~0x00008000u;
+  _has_bits_[0] &= ~0x00010000u;
 }
 void FileOptions::clear_cc_enable_arenas() {
   cc_enable_arenas_ = false;

+ 43 - 9
src/google/protobuf/descriptor.pb.h

@@ -2290,6 +2290,13 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message /* @@p
   bool py_generic_services() const;
   void set_py_generic_services(bool value);
 
+  // optional bool php_generic_services = 19 [default = false];
+  bool has_php_generic_services() const;
+  void clear_php_generic_services();
+  static const int kPhpGenericServicesFieldNumber = 19;
+  bool php_generic_services() const;
+  void set_php_generic_services(bool value);
+
   // optional bool deprecated = 23 [default = false];
   bool has_deprecated() const;
   void clear_deprecated();
@@ -2334,6 +2341,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message /* @@p
   void clear_has_java_generic_services();
   void set_has_py_generic_services();
   void clear_has_py_generic_services();
+  void set_has_php_generic_services();
+  void clear_has_php_generic_services();
   void set_has_deprecated();
   void clear_has_deprecated();
   void set_has_cc_enable_arenas();
@@ -2369,6 +2378,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message /* @@p
   bool cc_generic_services_;
   bool java_generic_services_;
   bool py_generic_services_;
+  bool php_generic_services_;
   bool deprecated_;
   bool cc_enable_arenas_;
   int optimize_for_;
@@ -6644,13 +6654,13 @@ inline void FileOptions::set_java_string_check_utf8(bool value) {
 
 // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
 inline bool FileOptions::has_optimize_for() const {
-  return (_has_bits_[0] & 0x00010000u) != 0;
+  return (_has_bits_[0] & 0x00020000u) != 0;
 }
 inline void FileOptions::set_has_optimize_for() {
-  _has_bits_[0] |= 0x00010000u;
+  _has_bits_[0] |= 0x00020000u;
 }
 inline void FileOptions::clear_has_optimize_for() {
-  _has_bits_[0] &= ~0x00010000u;
+  _has_bits_[0] &= ~0x00020000u;
 }
 inline void FileOptions::clear_optimize_for() {
   optimize_for_ = 1;
@@ -6802,15 +6812,39 @@ inline void FileOptions::set_py_generic_services(bool value) {
   // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.py_generic_services)
 }
 
+// optional bool php_generic_services = 19 [default = false];
+inline bool FileOptions::has_php_generic_services() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void FileOptions::set_has_php_generic_services() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void FileOptions::clear_has_php_generic_services() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void FileOptions::clear_php_generic_services() {
+  php_generic_services_ = false;
+  clear_has_php_generic_services();
+}
+inline bool FileOptions::php_generic_services() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.php_generic_services)
+  return php_generic_services_;
+}
+inline void FileOptions::set_php_generic_services(bool value) {
+  set_has_php_generic_services();
+  php_generic_services_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.php_generic_services)
+}
+
 // optional bool deprecated = 23 [default = false];
 inline bool FileOptions::has_deprecated() const {
-  return (_has_bits_[0] & 0x00004000u) != 0;
+  return (_has_bits_[0] & 0x00008000u) != 0;
 }
 inline void FileOptions::set_has_deprecated() {
-  _has_bits_[0] |= 0x00004000u;
+  _has_bits_[0] |= 0x00008000u;
 }
 inline void FileOptions::clear_has_deprecated() {
-  _has_bits_[0] &= ~0x00004000u;
+  _has_bits_[0] &= ~0x00008000u;
 }
 inline void FileOptions::clear_deprecated() {
   deprecated_ = false;
@@ -6828,13 +6862,13 @@ inline void FileOptions::set_deprecated(bool value) {
 
 // optional bool cc_enable_arenas = 31 [default = false];
 inline bool FileOptions::has_cc_enable_arenas() const {
-  return (_has_bits_[0] & 0x00008000u) != 0;
+  return (_has_bits_[0] & 0x00010000u) != 0;
 }
 inline void FileOptions::set_has_cc_enable_arenas() {
-  _has_bits_[0] |= 0x00008000u;
+  _has_bits_[0] |= 0x00010000u;
 }
 inline void FileOptions::clear_has_cc_enable_arenas() {
-  _has_bits_[0] &= ~0x00008000u;
+  _has_bits_[0] &= ~0x00010000u;
 }
 inline void FileOptions::clear_cc_enable_arenas() {
   cc_enable_arenas_ = false;

+ 1 - 0
src/google/protobuf/descriptor.proto

@@ -351,6 +351,7 @@ message FileOptions {
   optional bool cc_generic_services = 16 [default=false];
   optional bool java_generic_services = 17 [default=false];
   optional bool py_generic_services = 18 [default=false];
+  optional bool php_generic_services = 19 [default=false];
 
   // Is this file deprecated?
   // Depending on the target platform, this can emit Deprecated annotations

+ 1 - 1
tests.sh

@@ -346,7 +346,7 @@ generate_php_test_proto() {
   # Generate test file
   rm -rf generated
   mkdir generated
-  ../../src/protoc --php_out=generated proto/test.proto proto/test_include.proto proto/test_no_namespace.proto proto/test_prefix.proto proto/test_php_namespace.proto proto/test_empty_php_namespace.proto
+  ../../src/protoc --php_out=generated proto/test.proto proto/test_include.proto proto/test_no_namespace.proto proto/test_prefix.proto proto/test_php_namespace.proto proto/test_empty_php_namespace.proto proto/test_service.proto proto/test_service_namespace.proto
   pushd ../../src
   ./protoc --php_out=../php/tests/generated google/protobuf/empty.proto
   ./protoc --php_out=../php/tests/generated -I../php/tests -I. ../php/tests/proto/test_import_descriptor_proto.proto