Change enum string name for reserved words (#9780)

* Change enum string name for reserved words

Update PHP descriptor protos

* conditionally generate value compat code
diff --git a/php/tests/GeneratedClassTest.php b/php/tests/GeneratedClassTest.php
index 3c4ef13..37c33df 100644
--- a/php/tests/GeneratedClassTest.php
+++ b/php/tests/GeneratedClassTest.php
@@ -291,6 +291,10 @@
         // Test Enum methods
         $this->assertEquals('ONE', TestEnum::name(1));
         $this->assertEquals(1, TestEnum::value('ONE'));
+        $this->assertEquals('ECHO', TestEnum::name(3));
+        $this->assertEquals(3, TestEnum::value('ECHO'));
+        // Backwards compat value lookup by prefixed-name.
+        $this->assertEquals(3, TestEnum::value('PBECHO'));
     }
 
     public function testInvalidEnumValueThrowsException()
diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc
index 1426112..135a92f 100644
--- a/src/google/protobuf/compiler/php/php_generator.cc
+++ b/src/google/protobuf/compiler/php/php_generator.cc
@@ -1373,11 +1373,18 @@
       "name", fullname);
   Indent(&printer);
 
+  bool hasReserved = false;
   for (int i = 0; i < en->value_count(); i++) {
     const EnumValueDescriptor* value = en->value(i);
     GenerateEnumValueDocComment(&printer, value);
+
+    std::string prefix = ConstantNamePrefix(value->name());
+    if (!prefix.empty()) {
+      hasReserved = true;
+    }
+
     printer.Print("const ^name^ = ^number^;\n",
-                  "name", ConstantNamePrefix(value->name()) + value->name(),
+                  "name", prefix + value->name(),
                   "number", IntToString(value->number()));
   }
 
@@ -1385,8 +1392,9 @@
   Indent(&printer);
   for (int i = 0; i < en->value_count(); i++) {
     const EnumValueDescriptor* value = en->value(i);
-    printer.Print("self::^name^ => '^name^',\n",
-                  "name", ConstantNamePrefix(value->name()) + value->name());
+    printer.Print("self::^constant^ => '^name^',\n",
+                  "constant", ConstantNamePrefix(value->name()) + value->name(),
+                  "name", value->name());
   }
   Outdent(&printer);
   printer.Print("];\n");
@@ -1416,12 +1424,22 @@
   printer.Print("$const = __CLASS__ . '::' . strtoupper($name);\n"
                 "if (!defined($const)) {\n");
   Indent(&printer);
+  if (hasReserved) {
+    printer.Print("$pbconst =  __CLASS__. '::PB' . strtoupper($name);\n"
+                "if (!defined($pbconst)) {\n");
+    Indent(&printer);
+  }
   printer.Print("throw new UnexpectedValueException(sprintf(\n");
   Indent(&printer);
   Indent(&printer);
   printer.Print("'Enum %s has no value defined for name %s', __CLASS__, $name));\n");
   Outdent(&printer);
   Outdent(&printer);
+  if (hasReserved) {
+    Outdent(&printer);
+    printer.Print("}\n"
+                  "return constant($pbconst);\n");
+  }
   Outdent(&printer);
   printer.Print("}\n"
                 "return constant($const);\n");