Use legacy name in php runtime (#4741)

* Use legacy name in php runtime

Old generated code cannot work with new runtime, because the new runtime
assumes new class name for nested message. For details see #4738.

* Remove unused method
diff --git a/php/src/Google/Protobuf/Internal/Descriptor.php b/php/src/Google/Protobuf/Internal/Descriptor.php
index ee3a8bd..21ac5de 100644
--- a/php/src/Google/Protobuf/Internal/Descriptor.php
+++ b/php/src/Google/Protobuf/Internal/Descriptor.php
@@ -44,6 +44,7 @@
     private $nested_type = [];
     private $enum_type = [];
     private $klass;
+    private $legacy_klass;
     private $options;
     private $oneof_decl = [];
 
@@ -151,6 +152,16 @@
         return $this->klass;
     }
 
+    public function setLegacyClass($klass)
+    {
+        $this->legacy_klass = $klass;
+    }
+
+    public function getLegacyClass()
+    {
+        return $this->legacy_klass;
+    }
+
     public function setOptions($options)
     {
         $this->options = $options;
@@ -167,16 +178,19 @@
 
         $message_name_without_package  = "";
         $classname = "";
+        $legacy_classname = "";
         $fullname = "";
         GPBUtil::getFullClassName(
             $proto,
             $containing,
             $file_proto,
             $message_name_without_package,
+            $legacy_classname,
             $classname,
             $fullname);
         $desc->setFullName($fullname);
         $desc->setClass($classname);
+        $desc->setLegacyClass($legacy_classname);
         $desc->setOptions($proto->getOptions());
 
         foreach ($proto->getField() as $field_proto) {
diff --git a/php/src/Google/Protobuf/Internal/DescriptorPool.php b/php/src/Google/Protobuf/Internal/DescriptorPool.php
index 304c161..9b4dcc0 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorPool.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorPool.php
@@ -92,6 +92,7 @@
         $this->proto_to_class[$descriptor->getFullName()] =
             $descriptor->getClass();
         $this->class_to_desc[$descriptor->getClass()] = $descriptor;
+        $this->class_to_desc[$descriptor->getLegacyClass()] = $descriptor;
         foreach ($descriptor->getNestedType() as $nested_type) {
             $this->addDescriptor($nested_type);
         }
@@ -105,6 +106,7 @@
         $this->proto_to_class[$descriptor->getFullName()] =
             $descriptor->getClass();
         $this->class_to_enum_desc[$descriptor->getClass()] = $descriptor;
+        $this->class_to_enum_desc[$descriptor->getLegacyClass()] = $descriptor;
     }
 
     public function getDescriptorByClassName($klass)
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptor.php b/php/src/Google/Protobuf/Internal/EnumDescriptor.php
index 01649fe..82a4276 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptor.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptor.php
@@ -9,6 +9,7 @@
     use HasPublicDescriptorTrait;
 
     private $klass;
+    private $legacy_klass;
     private $full_name;
     private $value;
     private $name_to_value;
@@ -66,12 +67,23 @@
         return $this->klass;
     }
 
+    public function setLegacyClass($klass)
+    {
+        $this->legacy_klass = $klass;
+    }
+
+    public function getLegacyClass()
+    {
+        return $this->legacy_klass;
+    }
+
     public static function buildFromProto($proto, $file_proto, $containing)
     {
         $desc = new EnumDescriptor();
 
         $enum_name_without_package  = "";
         $classname = "";
+        $legacy_classname = "";
         $fullname = "";
         GPBUtil::getFullClassName(
             $proto,
@@ -79,9 +91,11 @@
             $file_proto,
             $enum_name_without_package,
             $classname,
+            $legacy_classname,
             $fullname);
         $desc->setFullName($fullname);
         $desc->setClass($classname);
+        $desc->setLegacyClass($legacy_classname);
         $values = $proto->getValue();
         foreach ($values as $value) {
             $desc->addValue($value->getNumber(), $value);
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 023b07f..ec0bf6b 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -215,9 +215,10 @@
                     "Expect repeated field of different type.");
             }
             if ($var->getType() === GPBType::MESSAGE &&
-                $var->getClass() !== $klass) {
+                $var->getClass() !== $klass &&
+                $var->getLegacyClass() !== $klass) {
                 throw new \Exception(
-                    "Expect repeated field of different message.");
+                    "Expect repeated field of " . $klass . ".");
             }
             return $var;
         }
@@ -242,9 +243,10 @@
                 throw new \Exception("Expect map field of value type.");
             }
             if ($var->getValueType() === GPBType::MESSAGE &&
-                $var->getValueClass() !== $klass) {
+                $var->getValueClass() !== $klass &&
+                $var->getLegacyValueClass() !== $klass) {
                 throw new \Exception(
-                    "Expect map field of different value message.");
+                    "Expect map field of " . $klass . ".");
             }
             return $var;
         }
@@ -299,6 +301,14 @@
         return "";
     }
 
+    public static function getLegacyClassNameWithoutPackage(
+        $name,
+        $file_proto)
+    {
+        $classname = implode('_', explode('.', $name));
+        return static::getClassNamePrefix($classname, $file_proto) . $classname;
+    }
+
     public static function getClassNameWithoutPackage(
         $name,
         $file_proto)
@@ -316,6 +326,7 @@
         $file_proto,
         &$message_name_without_package,
         &$classname,
+        &$legacy_classname,
         &$fullname)
     {
         // Full name needs to start with '.'.
@@ -334,21 +345,28 @@
 
         $class_name_without_package =
             static::getClassNameWithoutPackage($message_name_without_package, $file_proto);
+        $legacy_class_name_without_package =
+            static::getLegacyClassNameWithoutPackage(
+                $message_name_without_package, $file_proto);
 
         $option = $file_proto->getOptions();
         if (!is_null($option) && $option->hasPhpNamespace()) {
             $namespace = $option->getPhpNamespace();
             if ($namespace !== "") {
                 $classname = $namespace . "\\" . $class_name_without_package;
+                $legacy_classname =
+                    $namespace . "\\" . $legacy_class_name_without_package;
                 return;
             } else {
                 $classname = $class_name_without_package;
+                $legacy_classname = $legacy_class_name_without_package;
                 return;
             }
         }
 
         if ($package === "") {
             $classname = $class_name_without_package;
+            $legacy_classname = $legacy_class_name_without_package;
         } else {
             $parts = array_map('ucwords', explode('.', $package));
             foreach ($parts as $i => $part) {
@@ -358,6 +376,9 @@
                 implode('\\', $parts) .
                 "\\".self::getClassNamePrefix($class_name_without_package,$file_proto).
                 $class_name_without_package;
+            $legacy_classname =
+                implode('\\', array_map('ucwords', explode('.', $package))).
+                "\\".$legacy_class_name_without_package;
         }
     }
 
diff --git a/php/src/Google/Protobuf/Internal/MapField.php b/php/src/Google/Protobuf/Internal/MapField.php
index 38736da..f7d7b71 100644
--- a/php/src/Google/Protobuf/Internal/MapField.php
+++ b/php/src/Google/Protobuf/Internal/MapField.php
@@ -58,7 +58,11 @@
     /**
      * @ignore
      */
-    private $value_klass;
+    private $klass;
+    /**
+     * @ignore
+     */
+    private $legacy_klass;
 
     /**
      * Constructs an instance of MapField.
@@ -75,6 +79,17 @@
         $this->key_type = $key_type;
         $this->value_type = $value_type;
         $this->klass = $klass;
+
+        if ($this->value_type == GPBType::MESSAGE) {
+            $pool = DescriptorPool::getGeneratedPool();
+            $desc = $pool->getDescriptorByClassName($klass);
+            if ($desc == NULL) {
+                new $klass;  // No msg class instance has been created before.
+                $desc = $pool->getDescriptorByClassName($klass);
+            }
+            $this->klass = $desc->getClass();
+            $this->legacy_klass = $desc->getLegacyClass();
+        }
     }
 
     /**
@@ -102,6 +117,14 @@
     }
 
     /**
+     * @ignore
+     */
+    public function getLegacyValueClass()
+    {
+        return $this->legacy_klass;
+    }
+
+    /**
      * Return the element at the given key.
      *
      * This will also be called for: $ele = $arr[$key]
diff --git a/php/src/Google/Protobuf/Internal/RepeatedField.php b/php/src/Google/Protobuf/Internal/RepeatedField.php
index 797b3b3..e0ddef5 100644
--- a/php/src/Google/Protobuf/Internal/RepeatedField.php
+++ b/php/src/Google/Protobuf/Internal/RepeatedField.php
@@ -59,6 +59,10 @@
      * @ignore
      */
     private $klass;
+    /**
+     * @ignore
+     */
+    private $legacy_klass;
 
     /**
      * Constructs an instance of RepeatedField.
@@ -71,7 +75,16 @@
     {
         $this->container = [];
         $this->type = $type;
-        $this->klass = $klass;
+        if ($this->type == GPBType::MESSAGE) {
+            $pool = DescriptorPool::getGeneratedPool();
+            $desc = $pool->getDescriptorByClassName($klass);
+            if ($desc == NULL) {
+                new $klass;  // No msg class instance has been created before.
+                $desc = $pool->getDescriptorByClassName($klass);
+            }
+            $this->klass = $desc->getClass();
+            $this->legacy_klass = $desc->getLegacyClass();
+        }
     }
 
     /**
@@ -91,6 +104,14 @@
     }
 
     /**
+     * @ignore
+     */
+    public function getLegacyClass()
+    {
+        return $this->legacy_klass;
+    }
+
+    /**
      * Return the element at the given index.
      *
      * This will also be called for: $ele = $arr[0]
diff --git a/php/tests/compatibility_test.sh b/php/tests/compatibility_test.sh
index 7caa46e..b5b255e 100755
--- a/php/tests/compatibility_test.sh
+++ b/php/tests/compatibility_test.sh
@@ -2,12 +2,14 @@
 
 function use_php() {
   VERSION=$1
-  PHP=`which php`
-  PHP_CONFIG=`which php-config`
-  PHPIZE=`which phpize`
-  ln -sfn "/usr/local/php-${VERSION}/bin/php" $PHP
-  ln -sfn "/usr/local/php-${VERSION}/bin/php-config" $PHP_CONFIG
-  ln -sfn "/usr/local/php-${VERSION}/bin/phpize" $PHPIZE
+
+  OLD_PATH=$PATH
+  OLD_CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH
+  OLD_C_INCLUDE_PATH=$C_INCLUDE_PATH
+
+  export PATH=/usr/local/php-${VERSION}/bin:$OLD_PATH
+  export CPLUS_INCLUDE_PATH=/usr/local/php-${VERSION}/include/php/main:/usr/local/php-${VERSION}/include/php/:$OLD_CPLUS_INCLUDE_PATH
+  export C_INCLUDE_PATH=/usr/local/php-${VERSION}/include/php/main:/usr/local/php-${VERSION}/include/php/:$OLD_C_INCLUDE_PATH
 }
 
 function generate_proto() {
@@ -18,7 +20,22 @@
   mkdir generated
 
   $PROTOC1 --php_out=generated proto/test_include.proto
-  $PROTOC2 --php_out=generated proto/test.proto proto/test_no_namespace.proto proto/test_prefix.proto
+  $PROTOC2 --php_out=generated                 \
+    proto/test.proto                           \
+    proto/test_no_namespace.proto              \
+    proto/test_prefix.proto                    \
+    proto/test_php_namespace.proto             \
+    proto/test_empty_php_namespace.proto       \
+    proto/test_reserved_enum_lower.proto       \
+    proto/test_reserved_enum_upper.proto       \
+    proto/test_reserved_enum_value_lower.proto \
+    proto/test_reserved_enum_value_upper.proto \
+    proto/test_reserved_message_lower.proto    \
+    proto/test_reserved_message_upper.proto    \
+    proto/test_service.proto                   \
+    proto/test_service_namespace.proto         \
+    proto/test_descriptors.proto
+
   pushd ../../src
   $PROTOC2 --php_out=../php/tests/generated -I../php/tests -I. ../php/tests/proto/test_import_descriptor_proto.proto
   popd
@@ -52,9 +69,9 @@
 
 # The old version of protobuf that we are testing compatibility against.
 case "$1" in
-  ""|3.3.0)
-    OLD_VERSION=3.3.0
-    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/3.3.0/protoc-3.3.0-linux-x86_64.exe
+  ""|3.5.0)
+    OLD_VERSION=3.5.0
+    OLD_VERSION_PROTOC=http://repo1.maven.org/maven2/com/google/protobuf/protoc/$OLD_VERSION/protoc-$OLD_VERSION-linux-x86_64.exe
     ;;
   *)
     echo "[ERROR]: Unknown version number: $1"
@@ -81,7 +98,7 @@
 popd
 
 # Build and copy the new runtime
-use_php 5.5
+use_php 7.1
 pushd ../ext/google/protobuf
 make clean || true
 phpize && ./configure && make
@@ -99,12 +116,12 @@
 NEW_PROTOC=`pwd`/../../src/protoc
 OLD_PROTOC=`pwd`/old_protoc
 cd protobuf/php
-cp -r /usr/local/vendor-5.5 vendor
-wget https://phar.phpunit.de/phpunit-4.8.0.phar -O /usr/bin/phpunit
+composer install
 
 # Remove implementation detail tests.
 tests=( array_test.php encode_decode_test.php generated_class_test.php map_field_test.php well_known_test.php )
 sed -i.bak '/php_implementation_test.php/d' phpunit.xml
+sed -i.bak '/generated_phpdoc_test.php/d' phpunit.xml
 for t in "${tests[@]}"
 do
   remove_error_test tests/$t
@@ -118,7 +135,7 @@
 generate_proto $OLD_PROTOC $OLD_PROTOC
 ./test.sh
 pushd ..
-phpunit
+./vendor/bin/phpunit
 popd
 
 # Test A.2:
@@ -127,7 +144,7 @@
 generate_proto $NEW_PROTOC $OLD_PROTOC
 ./test.sh
 pushd ..
-phpunit
+./vendor/bin/phpunit
 popd
 
 # Test A.3:
@@ -136,5 +153,5 @@
 generate_proto $OLD_PROTOC $NEW_PROTOC
 ./test.sh
 pushd ..
-phpunit
+./vendor/bin/phpunit
 popd