[THRIFT-5757] Unit tests for php lib
Client: php
Patch: Volodymyr Panivko

This closes #2951
diff --git a/lib/php/lib/Protocol/TCompactProtocol.php b/lib/php/lib/Protocol/TCompactProtocol.php
index 1af2a27..ebe32e5 100644
--- a/lib/php/lib/Protocol/TCompactProtocol.php
+++ b/lib/php/lib/Protocol/TCompactProtocol.php
@@ -154,6 +154,7 @@
             $shift += 7;
         }
 
+        #unreachable statement
         return $idx;
     }
 
diff --git a/lib/php/lib/Protocol/TJSONProtocol.php b/lib/php/lib/Protocol/TJSONProtocol.php
index e1412cc..cfd3c8b 100644
--- a/lib/php/lib/Protocol/TJSONProtocol.php
+++ b/lib/php/lib/Protocol/TJSONProtocol.php
@@ -23,6 +23,7 @@
 
 namespace Thrift\Protocol;
 
+use Thrift\Exception\TException;
 use Thrift\Type\TType;
 use Thrift\Exception\TProtocolException;
 use Thrift\Protocol\JSON\BaseContext;
@@ -186,8 +187,6 @@
         $this->reader_ = new LookaheadReader($this);
     }
 
-    private $tmpbuf_ = array(4);
-
     public function readJSONSyntaxChar($b)
     {
         $ch = $this->reader_->read();
@@ -197,68 +196,6 @@
         }
     }
 
-    private function hexVal($s)
-    {
-        for ($i = 0; $i < strlen($s); $i++) {
-            $ch = substr($s, $i, 1);
-
-            if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) {
-                throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA);
-            }
-        }
-
-        return hexdec($s);
-    }
-
-    private function hexChar($val)
-    {
-        return dechex($val);
-    }
-
-    private function hasJSONUnescapedUnicode()
-    {
-        if (PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    private function unescapedUnicode($str)
-    {
-        if ($this->hasJSONUnescapedUnicode()) {
-            return json_encode($str, JSON_UNESCAPED_UNICODE);
-        }
-
-        $json = json_encode($str);
-
-        /*
-         * Unescaped character outside the Basic Multilingual Plane
-         * High surrogate: 0xD800 - 0xDBFF
-         * Low surrogate: 0xDC00 - 0xDFFF
-         */
-        $json = preg_replace_callback(
-            '/\\\\u(d[89ab][0-9a-f]{2})\\\\u(d[cdef][0-9a-f]{2})/i',
-            function ($matches) {
-                return mb_convert_encoding(pack('H*', $matches[1] . $matches[2]), 'UTF-8', 'UTF-16BE');
-            },
-            $json
-        );
-
-        /*
-         * Unescaped characters within the Basic Multilingual Plane
-         */
-        $json = preg_replace_callback(
-            '/\\\\u([0-9a-f]{4})/i',
-            function ($matches) {
-                return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
-            },
-            $json
-        );
-
-        return $json;
-    }
-
     private function writeJSONString($b)
     {
         $this->context_->write();
@@ -267,7 +204,7 @@
             $this->trans_->write(self::QUOTE);
         }
 
-        $this->trans_->write($this->unescapedUnicode($b));
+        $this->trans_->write(json_encode($b, JSON_UNESCAPED_UNICODE));
 
         if (is_numeric($b) && $this->context_->escapeNum()) {
             $this->trans_->write(self::QUOTE);
@@ -297,6 +234,7 @@
             $this->trans_->write(self::QUOTE);
         }
 
+        #TODO add compatibility with NAN and INF
         $this->trans_->write(json_encode($num));
 
         if ($this->context_->escapeNum()) {
@@ -304,14 +242,6 @@
         }
     }
 
-    private function writeJSONBase64($data)
-    {
-        $this->context_->write();
-        $this->trans_->write(self::QUOTE);
-        $this->trans_->write(json_encode(base64_encode($data)));
-        $this->trans_->write(self::QUOTE);
-    }
-
     private function writeJSONObjectStart()
     {
         $this->context_->write();
@@ -481,18 +411,6 @@
         }
     }
 
-    private function readJSONBase64()
-    {
-        $arr = $this->readJSONString(false);
-        $data = base64_decode($arr, true);
-
-        if ($data === false) {
-            throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA);
-        }
-
-        return $data;
-    }
-
     private function readJSONObjectStart()
     {
         $this->context_->read();
diff --git a/lib/php/lib/Protocol/TSimpleJSONProtocol.php b/lib/php/lib/Protocol/TSimpleJSONProtocol.php
index 1cf1f64..22f1742 100644
--- a/lib/php/lib/Protocol/TSimpleJSONProtocol.php
+++ b/lib/php/lib/Protocol/TSimpleJSONProtocol.php
@@ -115,6 +115,7 @@
             $this->trans_->write(self::QUOTE);
         }
 
+        #TODO add compatibility with NAN and INF
         $this->trans_->write(json_encode((float)$num));
 
         if ($isMapKey) {
diff --git a/lib/php/phpunit.xml b/lib/php/phpunit.xml
index 2cbea95..58e8f5d 100644
--- a/lib/php/phpunit.xml
+++ b/lib/php/phpunit.xml
@@ -18,7 +18,7 @@
  under the License.
 -->
 <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         bootstrap="../../vendor/autoload.php"
+         bootstrap="test/bootstrap.php"
          cacheResult="false"
          colors="true"
          convertErrorsToExceptions="true"
@@ -34,8 +34,11 @@
         </whitelist>
     </filter>
     <testsuites>
-        <testsuite name="Thrift PHP Test Suite">
+        <testsuite name="Thrift PHP Unit Test Suite">
             <directory>./test/Unit</directory>
         </testsuite>
+        <testsuite name="Thrift PHP Integration Test Suite">
+            <directory>./test/Integration</directory>
+        </testsuite>
     </testsuites>
 </phpunit>
diff --git a/lib/php/test/Fixtures/Fixtures.php b/lib/php/test/Fixtures/Fixtures.php
deleted file mode 100644
index d48be40..0000000
--- a/lib/php/test/Fixtures/Fixtures.php
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-namespace Test\Thrift\Fixtures;
-
-use ThriftTest\Xtruct;
-use ThriftTest\Xtruct2;
-use ThriftTest\Numberz;
-use ThriftTest\Insanity;
-
-class Fixtures
-{
-    public static $bufsize = 8192; //big enough to read biggest serialized Fixture arg.
-    public static $testArgs = array();
-
-    public static function populateTestArgs()
-    {
-        self::$testArgs['testString1'] = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
-
-        self::$testArgs['testString2'] =
-            "quote: \\\" backslash:" .
-            " forwardslash-escaped: \\/ " .
-            " backspace: \b formfeed: \f newline: \n return: \r tab: " .
-            " now-all-of-them-together: \"\\\/\b\n\r\t" .
-            " now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><";
-
-        self::$testArgs['testString3'] =
-            "string that ends in double-backslash \\\\";
-
-        self::$testArgs['testUnicodeStringWithNonBMP'] =
-            "สวัสดี/𝒯";
-
-        self::$testArgs['testDouble'] = 3.1415926535898;
-
-        // TODO: add testBinary() call
-
-        self::$testArgs['testByte'] = 0x01;
-
-        self::$testArgs['testI32'] = pow(2, 30);
-
-        if (PHP_INT_SIZE == 8) {
-            self::$testArgs['testI64'] = pow(2, 60);
-        } else {
-            self::$testArgs['testI64'] = "1152921504606847000";
-        }
-
-        self::$testArgs['testStruct'] =
-            new Xtruct(
-                array(
-                    'string_thing' => 'worked',
-                    'byte_thing' => 0x01,
-                    'i32_thing' => pow(2, 30),
-                    'i64_thing' => self::$testArgs['testI64']
-                )
-            );
-
-        self::$testArgs['testNestNested'] =
-            new Xtruct(
-                array(
-                    'string_thing' => 'worked',
-                    'byte_thing' => 0x01,
-                    'i32_thing' => pow(2, 30),
-                    'i64_thing' => self::$testArgs['testI64']
-                )
-            );
-
-        self::$testArgs['testNest'] =
-            new Xtruct2(
-                array(
-                    'byte_thing' => 0x01,
-                    'struct_thing' => self::$testArgs['testNestNested'],
-                    'i32_thing' => pow(2, 15)
-                )
-            );
-
-        self::$testArgs['testMap'] =
-            array(
-                7 => 77,
-                8 => 88,
-                9 => 99
-            );
-
-        self::$testArgs['testStringMap'] =
-            array(
-                "a" => "123",
-                "a b" => "with spaces ",
-                "same" => "same",
-                "0" => "numeric key",
-                "longValue" => self::$testArgs['testString1'],
-                self::$testArgs['testString1'] => "long key"
-            );
-
-        self::$testArgs['testSet'] = array(1 => true, 5 => true, 6 => true);
-
-        self::$testArgs['testList'] = array(1, 2, 3);
-
-        self::$testArgs['testEnum'] = Numberz::ONE;
-
-        self::$testArgs['testTypedef'] = 69;
-
-        self::$testArgs['testMapMapExpectedResult'] =
-            array(
-                4 => array(
-                    1 => 1,
-                    2 => 2,
-                    3 => 3,
-                    4 => 4,
-                ),
-                -4 => array(
-                    -4 => -4,
-                    -3 => -3,
-                    -2 => -2,
-                    -1 => -1
-                )
-            );
-
-        // testInsanity ... takes a few steps to set up!
-
-        $xtruct1 =
-            new Xtruct(
-                array(
-                    'string_thing' => 'Goodbye4',
-                    'byte_thing' => 4,
-                    'i32_thing' => 4,
-                    'i64_thing' => 4
-                )
-            );
-
-        $xtruct2 =
-            new Xtruct(
-                array(
-                    'string_thing' => 'Hello2',
-                    'byte_thing' => 2,
-                    'i32_thing' => 2,
-                    'i64_thing' => 2
-                )
-            );
-
-        $userMap =
-            array(
-                Numberz::FIVE => 5,
-                Numberz::EIGHT => 8
-            );
-
-        $insanity2 =
-            new Insanity(
-                array(
-                    'userMap' => $userMap,
-                    'xtructs' => array($xtruct1, $xtruct2)
-                )
-            );
-
-        $insanity3 = $insanity2;
-
-        $insanity6 =
-            new Insanity(
-                array(
-                    'userMap' => null,
-                    'xtructs' => null
-                )
-            );
-
-        self::$testArgs['testInsanityExpectedResult'] =
-            array(
-                "1" => array(
-                    Numberz::TWO => $insanity2,
-                    Numberz::THREE => $insanity3
-                ),
-                "2" => array(
-                    Numberz::SIX => $insanity6
-                )
-            );
-    }
-}
diff --git a/lib/php/test/Fixtures/TJSONProtocolFixtures.php b/lib/php/test/Fixtures/TJSONProtocolFixtures.php
deleted file mode 100644
index 77fb270..0000000
--- a/lib/php/test/Fixtures/TJSONProtocolFixtures.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-namespace Test\Thrift\Fixtures;
-
-class TJSONProtocolFixtures
-{
-    public static $testArgsJSON = array();
-
-    public static function populateTestArgsJSON()
-    {
-        self::$testArgsJSON['testVoid'] = '{}';
-
-        self::$testArgsJSON['testString1'] = '{"1":{"str":"Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe\'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски \/ Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча\/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"}}';
-
-        self::$testArgsJSON['testString2'] = '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}';
-
-        self::$testArgsJSON['testString3'] = '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}';
-
-        self::$testArgsJSON['testUnicodeStringWithNonBMP'] = '{"1":{"str":"สวัสดี\/𝒯"}}';
-
-        self::$testArgsJSON['testDouble'] = '{"1":{"dbl":3.1415926535898}}';
-
-        self::$testArgsJSON['testByte'] = '{"1":{"i8":1}}';
-
-        self::$testArgsJSON['testI32'] = '{"1":{"i32":1073741824}}';
-
-        if (PHP_INT_SIZE == 8) {
-            self::$testArgsJSON['testI64'] = '{"1":{"i64":' . pow(2, 60) . '}}';
-            self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}}}';
-            self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}},"3":{"i32":32768}}}}';
-        } else {
-            self::$testArgsJSON['testI64'] = '{"1":{"i64":1152921504606847000}}';
-            self::$testArgsJSON['testStruct'] = '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}';
-            self::$testArgsJSON['testNest'] = '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}';
-        }
-
-        self::$testArgsJSON['testMap'] = '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}';
-
-        self::$testArgsJSON['testStringMap'] = '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}';
-
-        self::$testArgsJSON['testSet'] = '{"1":{"set":["i32",3,1,5,6]}}';
-
-        self::$testArgsJSON['testList'] = '{"1":{"lst":["i32",3,1,2,3]}}';
-
-        self::$testArgsJSON['testEnum'] = '{"1":{"i32":1}}';
-
-        self::$testArgsJSON['testTypedef'] = '{"1":{"i64":69}}';
-
-        self::$testArgsJSON['testMapMap'] = '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}';
-
-        self::$testArgsJSON['testInsanity'] = '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}';
-    }
-}
diff --git a/lib/php/test/Fixtures/TSimpleJSONProtocolFixtures.php b/lib/php/test/Fixtures/TSimpleJSONProtocolFixtures.php
deleted file mode 100644
index 0281a87..0000000
--- a/lib/php/test/Fixtures/TSimpleJSONProtocolFixtures.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-namespace Test\Thrift\Fixtures;
-
-class TSimpleJSONProtocolFixtures
-{
-    public static $testArgsJSON = array();
-
-    public static function populateTestArgsSimpleJSON()
-    {
-        self::$testArgsJSON['testVoid'] = '{}';
-
-        self::$testArgsJSON['testString1'] = '{"thing":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}';
-
-        self::$testArgsJSON['testString2'] = '{"thing":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}';
-
-        self::$testArgsJSON['testDouble'] = '{"thing":3.1415926535898}';
-
-        self::$testArgsJSON['testByte'] = '{"thing":1}';
-
-        self::$testArgsJSON['testI32'] = '{"thing":1073741824}';
-
-        if (PHP_INT_SIZE == 8) {
-            self::$testArgsJSON['testI64'] = '{"thing":' . pow(2, 60) . '}';
-            self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '}}';
-            self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '},"i32_thing":32768}}';
-        } else {
-            self::$testArgsJSON['testI64'] = '{"thing":1152921504606847000}';
-
-            self::$testArgsJSON['testStruct'] = '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000}}';
-            self::$testArgsJSON['testNest'] = '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000},"i32_thing":32768}}';
-        }
-
-        self::$testArgsJSON['testMap'] = '{"thing":{"7":77,"8":88,"9":99}}';
-
-        self::$testArgsJSON['testStringMap'] = '{"thing":{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}}';
-
-        self::$testArgsJSON['testSet'] = '{"thing":[1,5,6]}';
-
-        self::$testArgsJSON['testList'] = '{"thing":[1,2,3]}';
-
-        self::$testArgsJSON['testEnum'] = '{"thing":1}';
-
-        self::$testArgsJSON['testTypedef'] = '{"thing":69}';
-    }
-}
diff --git a/lib/php/test/Unit/BaseValidatorTest.php b/lib/php/test/Integration/BaseValidatorTest.php
similarity index 75%
rename from lib/php/test/Unit/BaseValidatorTest.php
rename to lib/php/test/Integration/BaseValidatorTest.php
index 4404e72..ae9d584 100644
--- a/lib/php/test/Unit/BaseValidatorTest.php
+++ b/lib/php/test/Integration/BaseValidatorTest.php
@@ -19,7 +19,7 @@
  * under the License.
  */
 
-namespace Test\Thrift\Unit;
+namespace Test\Thrift\Integration;
 
 use PHPUnit\Framework\TestCase;
 use Thrift\Exception\TProtocolException;
@@ -28,38 +28,41 @@
 
 abstract class BaseValidatorTest extends TestCase
 {
+    abstract public function getNsGlobal();
+
     public function testEmptyStructValidator()
     {
-        $this->assertNoReadValidator('ThriftTest\EmptyStruct');
-        $this->assertNoWriteValidator('ThriftTest\EmptyStruct');
+        $this->assertNoReadValidator($this->getNsGlobal() . '\ThriftTest\EmptyStruct');
+        $this->assertNoWriteValidator($this->getNsGlobal() . '\ThriftTest\EmptyStruct');
     }
 
     public function testBonkValidator()
     {
-        $this->assertNoReadValidator('ThriftTest\Bonk');
-        $this->assertHasWriteValidator('ThriftTest\Bonk');
+        $this->assertNoReadValidator($this->getNsGlobal() . '\ThriftTest\Bonk');
+        $this->assertHasWriteValidator($this->getNsGlobal() . '\ThriftTest\Bonk');
     }
 
     public function testStructAValidator()
     {
-        $this->assertHasReadValidator('ThriftTest\StructA');
-        $this->assertHasWriteValidator('ThriftTest\StructA');
+        $this->assertHasReadValidator($this->getNsGlobal() . '\ThriftTest\StructA');
+        $this->assertHasWriteValidator($this->getNsGlobal() . '\ThriftTest\StructA');
     }
 
     public function testUnionOfStringsValidator()
     {
-        $this->assertNoWriteValidator('TestValidators\UnionOfStrings');
+        $this->assertNoWriteValidator($this->getNsGlobal() . '\TestValidators\UnionOfStrings');
     }
 
     public function testServiceResultValidator()
     {
-        $this->assertNoReadValidator('TestValidators\TestService_test_result');
-        $this->assertNoWriteValidator('TestValidators\TestService_test_result');
+        $this->assertNoReadValidator($this->getNsGlobal() . '\TestValidators\TestService_test_result');
+        $this->assertNoWriteValidator($this->getNsGlobal() . '\TestValidators\TestService_test_result');
     }
 
     public function testReadEmpty()
     {
-        $bonk = new \ThriftTest\Bonk();
+        $className = $this->getNsGlobal() . '\ThriftTest\Bonk';
+        $bonk = new $className();
         $transport = new TMemoryBuffer("\000");
         $protocol = new TBinaryProtocol($transport);
         $bonk->read($protocol);
@@ -68,7 +71,8 @@
 
     public function testWriteEmpty()
     {
-        $bonk = new \ThriftTest\Bonk();
+        $className = $this->getNsGlobal() . '\ThriftTest\Bonk';
+        $bonk = new $className();
         $transport = new TMemoryBuffer();
         $protocol = new TBinaryProtocol($transport);
         try {
@@ -83,7 +87,8 @@
     public function testWriteWithMissingRequired()
     {
         // Check that we are not able to write StructA with a missing required field
-        $structa = new \ThriftTest\StructA();
+        $className = $this->getNsGlobal() . '\ThriftTest\StructA';
+        $structa = new $className();
         $transport = new TMemoryBuffer();
         $protocol = new TBinaryProtocol($transport);
 
@@ -100,7 +105,8 @@
     {
         $transport = new TMemoryBuffer(base64_decode('CwABAAAAA2FiYwA='));
         $protocol = new TBinaryProtocol($transport);
-        $structa = new \ThriftTest\StructA();
+        $className = $this->getNsGlobal() . '\ThriftTest\StructA';
+        $structa = new $className();
         $structa->read($protocol);
         $this->assertEquals("abc", $structa->s);
     }
@@ -109,7 +115,8 @@
     {
         $transport = new TMemoryBuffer();
         $protocol = new TBinaryProtocol($transport);
-        $structa = new \ThriftTest\StructA();
+        $className = $this->getNsGlobal() . '\ThriftTest\StructA';
+        $structa = new $className();
         $structa->s = "abc";
         $structa->write($protocol);
         $writeResult = base64_encode($transport->getBuffer());
diff --git a/lib/php/test/Integration/Lib/ClassLoader/ThriftClassLoaderTest.php b/lib/php/test/Integration/Lib/ClassLoader/ThriftClassLoaderTest.php
new file mode 100644
index 0000000..a43f5c6
--- /dev/null
+++ b/lib/php/test/Integration/Lib/ClassLoader/ThriftClassLoaderTest.php
@@ -0,0 +1,139 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Test\Thrift\Integration\Lib\ClassLoader;
+
+use phpmock\phpunit\PHPMock;
+use PHPUnit\Framework\TestCase;
+use Thrift\ClassLoader\ThriftClassLoader;
+
+/***
+ * This test depends on running the compiler against the ./Resources/ThriftTest.thrift file:
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:classmap,server,rest,nsglobal="Classmap" -r  --out ./Resources/packages/phpcm ./Resources/ThriftTest.thrift
+ */
+class ThriftClassLoaderTest extends TestCase
+{
+    use PHPMock;
+
+    /**
+     * @dataProvider registerDefinitionDataProvider
+     */
+    public function testRegisterDefinition(
+        $definitions,
+        $class,
+        $checkInterfaceExist = false,
+        $useApcu = false,
+        $apcuPrefix = null
+    ) {
+        $this->getFunctionMock('Thrift\ClassLoader', 'apcu_fetch')
+             ->expects($useApcu ? $this->any() : $this->never())
+             ->with($apcuPrefix . $class)
+             ->willReturn(false);
+
+        $this->getFunctionMock('Thrift\ClassLoader', 'apcu_store')
+            ->expects($useApcu ? $this->any() : $this->never())
+             ->with($apcuPrefix . $class, $this->anything())
+             ->willReturn(true);
+
+        $loader = new ThriftClassLoader($useApcu, $apcuPrefix);
+        foreach ($definitions as $namespace => $paths) {
+            $loader->registerDefinition($namespace, $paths);
+        }
+        $loader->register();
+
+        $loader->loadClass($class);
+        if ($checkInterfaceExist) {
+            $this->assertTrue(interface_exists($class, false), "->loadClass() loads '$class'");
+        } else {
+            $this->assertTrue(class_exists($class, false), "->loadClass() loads '$class'");
+        }
+    }
+
+    public function registerDefinitionDataProvider()
+    {
+        yield 'loadType' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => 'Classmap\ThriftTest\Xtruct',
+        ];
+        yield 'loadInterface' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => '\Classmap\ThriftTest\ThriftTestIf',
+            'checkInterfaceExist' => true,
+        ];
+        yield 'loadClient' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => '\Classmap\ThriftTest\ThriftTestClient',
+        ];
+        yield 'loadProcessor' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => '\Classmap\ThriftTest\ThriftTestProcessor',
+        ];
+        yield 'loadRest' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => '\Classmap\ThriftTest\ThriftTestRest',
+        ];
+        yield 'load_args' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => '\Classmap\ThriftTest\ThriftTest_testVoid_args',
+        ];
+        yield 'load_result' => [
+            'definitions' => [
+                'Classmap' => __DIR__ . '/../../../Resources/packages/phpcm',
+            ],
+            'class' => '\Classmap\ThriftTest\ThriftTest_testVoid_result',
+        ];
+        yield 'pathAsArray' => [
+            'definitions' => [
+                'Classmap' => [__DIR__ . '/../../../Resources/packages/phpcm'],
+            ],
+            'class' => 'Classmap\ThriftTest\Xtruct',
+        ];
+        yield 'severalDefinitions' => [
+            'definitions' => [
+                'Classmap\ThriftTest' => [__DIR__ . '/../../../Resources/packages/phpcm'],
+                'Classmap\TestValidators' => [__DIR__ . '/../../../Resources/packages/phpcm'],
+            ],
+            'class' => '\Classmap\TestValidators\TestServiceClient',
+        ];
+        yield 'useApcu' => [
+            'definitions' => [
+                'Classmap\ThriftTest' => [__DIR__ . '/../../../Resources/packages/phpcm'],
+                'Classmap\TestValidators' => [__DIR__ . '/../../../Resources/packages/phpcm'],
+            ],
+            'class' => '\Classmap\TestValidators\TestServiceClient',
+            'checkInterfaceExist' => false,
+            'useApcu' => true,
+            'apcuPrefix' => 'APCU_PREFIX',
+        ];
+    }
+}
diff --git a/lib/php/test/Integration/Lib/Protocol/TJSONProtocolTest.php b/lib/php/test/Integration/Lib/Protocol/TJSONProtocolTest.php
new file mode 100644
index 0000000..515cbdb
--- /dev/null
+++ b/lib/php/test/Integration/Lib/Protocol/TJSONProtocolTest.php
@@ -0,0 +1,646 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Test\Thrift\Integration\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Protocol\TJSONProtocol;
+use Thrift\Transport\TMemoryBuffer;
+use Basic\ThriftTest\Insanity;
+use Basic\ThriftTest\Numberz;
+use Basic\ThriftTest\Xtruct;
+use Basic\ThriftTest\Xtruct2;
+
+/***
+ * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:nsglobal="Basic" -r  --out ./Resources/packages/php ./Resources/ThriftTest.thrift
+ */
+class TJSONProtocolTest extends TestCase
+{
+    private const BUFFER_SIZE = 8192; //big enough to read biggest serialized Fixture arg.
+
+    private $transport;
+    private $protocol;
+
+    public static function setUpBeforeClass(): void
+    {
+        if (!is_dir(__DIR__ . '/../../../Resources/packages/php')) {
+            self::fail(
+                'Before running Integration test suite, you must run the Thrift compiler against the ThriftTest.thrift file in the ./Resources directory.'
+            );
+        }
+    }
+
+    public function setUp(): void
+    {
+        $this->transport = new TMemoryBuffer();
+        $this->protocol = new TJSONProtocol($this->transport);
+        $this->transport->open();
+    }
+
+    public function testMessageReadWrite()
+    {
+        $input = new TJSONProtocol(new TMemoryBuffer('[1,"testString",1,0,{"0":{"str":"successResponse"}}]'));
+        $service = new \Basic\ThriftTest\ThriftTestClient($input, $this->protocol);
+        $result = $service->testString('test');
+        $this->assertSame('successResponse', $result);
+    }
+
+    /**
+     * @dataProvider writeDataProvider
+     */
+    public function testWrite(
+        $argsClassName,
+        $argsValues,
+        $expected
+    ) {
+        $args = new $argsClassName($argsValues);
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(self::BUFFER_SIZE);
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function writeDataProvider()
+    {
+        if (!is_dir(__DIR__ . '/../../../Resources/packages/php')) {
+            throw new \RuntimeException(
+                'Before running Integration test suite, you must run the Thrift compiler against the ThriftTest.thrift file in the ./Resources directory.'
+            );
+        }
+
+        yield 'void' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testVoid_args::class,
+            'argsValues' => [],
+            'expected' => '{}',
+        ];
+        yield 'bool true' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testBool_args::class,
+            'argsValues' => [
+                'thing' => true,
+            ],
+            'expected' => '{"1":{"tf":1}}',
+        ];
+        yield 'bool false' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testBool_args::class,
+            'argsValues' => [
+                'thing' => false,
+            ],
+            'expected' => '{"1":{"tf":0}}',
+        ];
+        yield 'string1' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語",
+            ],
+            'expected' => '{"1":{"str":"Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe\'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски \/ Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча\/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"}}',
+        ];
+        yield 'string2' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "quote: \\\" backslash:" .
+                    " forwardslash-escaped: \\/ " .
+                    " backspace: \b formfeed: \f newline: \n return: \r tab: " .
+                    " now-all-of-them-together: \"\\\/\b\n\r\t" .
+                    " now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><",
+            ],
+            'expected' => '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}',
+        ];
+        yield 'string3' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "string that ends in double-backslash \\\\",
+            ],
+            'expected' => '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}',
+        ];
+        yield 'string4 testUnicodeStringWithNonBMP' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "สวัสดี/𝒯",
+            ],
+            'expected' => '{"1":{"str":"สวัสดี\/𝒯"}}',
+        ];
+        yield 'double' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsValues' => [
+                'thing' => 3.1415926535898,
+            ],
+            'expected' => '{"1":{"dbl":3.1415926535898}}',
+        ];
+        #TODO Should be fixed in future
+        yield 'double Nan' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsValues' => [
+                'thing' => NAN,
+            ],
+            'expected' => '{"1":{"dbl":}}',
+        ];
+        #TODO Should be fixed in future
+        yield 'double Infinity' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsValues' => [
+                'thing' => INF,
+            ],
+            'expected' => '{"1":{"dbl":}}',
+        ];
+        yield 'byte' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testByte_args::class,
+            'argsValues' => [
+                'thing' => 0x01,
+            ],
+            'expected' => '{"1":{"i8":1}}',
+        ];
+        yield 'i32' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testI32_args::class,
+            'argsValues' => [
+                'thing' => pow(2, 30),
+            ],
+            'expected' => '{"1":{"i32":1073741824}}',
+        ];
+        if (PHP_INT_SIZE == 8) {
+            yield 'i64_64Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testI64_args::class,
+                'argsValues' => [
+                    'thing' => pow(2, 60),
+                ],
+                'expected' => '{"1":{"i64":' . pow(2, 60) . '}}',
+            ];
+            yield 'struct_64Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testStruct_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct(
+                        [
+                            'string_thing' => 'worked',
+                            'byte_thing' => 0x01,
+                            'i32_thing' => pow(2, 30),
+                            'i64_thing' => pow(2, 60),
+                        ]
+                    ),
+                ],
+                'expected' => '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}}}',
+            ];
+            yield 'nest_64Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testNest_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct2(
+                        [
+                            'byte_thing' => 0x01,
+                            'struct_thing' => new Xtruct(
+                                [
+                                    'string_thing' => 'worked',
+                                    'byte_thing' => 0x01,
+                                    'i32_thing' => pow(2, 30),
+                                    'i64_thing' => pow(2, 60),
+                                ]
+                            ),
+                            'i32_thing' => pow(2, 15),
+                        ]
+                    ),
+                ],
+                'expected' => '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}},"3":{"i32":32768}}}}',
+            ];
+        } else {
+            yield 'i64_32Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testI64_args::class,
+                'argsValues' => [
+                    'thing' => "1152921504606847000",
+                ],
+                'expected' => '{"1":{"i64":1152921504606847000}}',
+            ];
+            yield 'struct_32Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testStruct_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct(
+                        [
+                            'string_thing' => 'worked',
+                            'byte_thing' => 0x01,
+                            'i32_thing' => pow(2, 30),
+                            'i64_thing' => pow(2, 60),
+                        ]
+                    ),
+                ],
+                'expected' => '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}',
+            ];
+            yield 'nest_32Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testNest_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct2(
+                        [
+                            'byte_thing' => 0x01,
+                            'struct_thing' => new Xtruct(
+                                [
+                                    'string_thing' => 'worked',
+                                    'byte_thing' => 0x01,
+                                    'i32_thing' => pow(2, 30),
+                                    'i64_thing' => '1152921504606847000',
+                                ]
+                            ),
+                            'i32_thing' => pow(2, 15),
+                        ]
+                    ),
+                ],
+                'expected' => '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}',
+            ];
+        }
+        yield 'map' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testMap_args::class,
+            'argsValues' => [
+                'thing' => [
+                    7 => 77,
+                    8 => 88,
+                    9 => 99,
+                ],
+            ],
+            'expected' => '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}',
+        ];
+        yield 'stringMap' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testStringMap_args::class,
+            'argsValues' => [
+                'thing' => [
+                    "a" => "123",
+                    "a b" => "with spaces ",
+                    "same" => "same",
+                    "0" => "numeric key",
+                    "longValue" => "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語",
+                    "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語" => "long key",
+                ],
+            ],
+            'expected' => '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe\'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски \/ Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча\/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語","Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe\'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски \/ Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча\/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語":"long key"}]}}',
+        ];
+        yield 'set' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testSet_args::class,
+            'argsValues' => [
+                'thing' => [1 => true, 5 => true, 6 => true],
+            ],
+            'expected' => '{"1":{"set":["i32",3,1,5,6]}}',
+        ];
+        yield 'list' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testList_args::class,
+            'argsValues' => [
+                'thing' => [1, 2, 3],
+            ],
+            'expected' =>  '{"1":{"lst":["i32",3,1,2,3]}}',
+        ];
+        yield 'enum' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testEnum_args::class,
+            'argsValues' => [
+                'thing' => \Basic\ThriftTest\Numberz::SIX,
+            ],
+            'expected' => '{"1":{"i32":6}}',
+        ];
+        yield 'typedef' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testTypedef_args::class,
+            'argsValues' => [
+                'thing' => 69,
+            ],
+            'expected' => '{"1":{"i64":69}}',
+        ];
+    }
+
+    /**
+     * @dataProvider readDataProvider
+     */
+    public function testRead(
+        $buffer,
+        $argsClassName,
+        $argsPropertyName,
+        $expectedValue,
+        $expectedResult
+    ): void {
+        $this->transport->write($buffer);
+        $args = new $argsClassName();
+        $result = $args->read($this->protocol);
+
+        $this->assertEquals($expectedResult, $result);
+
+        if (is_null($argsPropertyName)) {
+            $this->assertNull($argsPropertyName);
+        } elseif (is_float($expectedValue) && is_nan($expectedValue)) {
+            $this->assertNan($args->{$argsPropertyName});
+        } elseif (is_float($expectedValue) && is_infinite($expectedValue)) {
+            $this->assertEquals($expectedValue, $args->{$argsPropertyName});
+        } else {
+            $this->assertEquals($expectedValue, $args->{$argsPropertyName});
+        }
+    }
+
+    public function readDataProvider()
+    {
+        yield 'void' => [
+            'buffer' => '{}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testVoid_args::class,
+            'argsPropertyName' => null,
+            'expectedValue' => null,
+            'expectedResult' => 0,
+        ];
+        yield 'bool true' => [
+            'buffer' => '{"1":{"tf":1}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testBool_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => true,
+            'expectedResult' => 1,
+        ];
+        yield 'bool false' => [
+            'buffer' => '{"1":{"tf":0}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testBool_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => false,
+            'expectedResult' => 1,
+        ];
+        yield 'string1' => [
+            'buffer' => '{"1":{"str":"Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ \/ ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe\'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски \/ Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча\/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語",
+            'expectedResult' => 1,
+        ];
+        yield 'string2' => [
+            'buffer' => '{"1":{"str":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => "quote: \\\" backslash:" .
+                " forwardslash-escaped: \\/ " .
+                " backspace: \b formfeed: \f newline: \n return: \r tab: " .
+                " now-all-of-them-together: \"\\\/\b\n\r\t" .
+                " now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><",
+            'expectedResult' => 1,
+        ];
+        yield 'string3' => [
+            'buffer' => '{"1":{"str":"string that ends in double-backslash \\\\\\\\"}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => "string that ends in double-backslash \\\\",
+            'expectedResult' => 1,
+        ];
+        yield 'string4' => [
+            'buffer' => '{"1":{"str":"สวัสดี\/𝒯"}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => "สวัสดี/𝒯",
+            'expectedResult' => 1,
+        ];
+        yield 'double' => [
+            'buffer' => '{"1":{"dbl":3.1415926535898}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => 3.1415926535898,
+            'expectedResult' => 1,
+        ];
+        yield 'double Nan' => [
+            'buffer' => '{"1":{"dbl":"NaN"}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => NAN,
+            'expectedResult' => 1,
+        ];
+        yield 'double Infinity' => [
+            'buffer' => '{"1":{"dbl":"Infinity"}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => INF,
+            'expectedResult' => 1,
+        ];
+        yield 'byte' => [
+            'buffer' => '{"1":{"i8":1}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testByte_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => 0x01,
+            'expectedResult' => 1,
+        ];
+        yield 'i32' => [
+            'buffer' => '{"1":{"i32":1073741824}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testI32_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => pow(2, 30),
+            'expectedResult' => 1,
+        ];
+        if (PHP_INT_SIZE == 8) {
+            yield 'i64_64Architecture' => [
+                'buffer' => '{"1":{"i64":' . pow(2, 60) . '}}',
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testI64_args::class,
+                'argsPropertyName' => 'thing',
+                'expectedValue' => pow(2, 60),
+                'expectedResult' => 1,
+            ];
+            yield 'struct_64Architecture' => [
+                'buffer' => '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}}}',
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testStruct_args::class,
+                'argsPropertyName' => 'thing',
+                'expectedValue' => new Xtruct(
+                    array(
+                        'string_thing' => 'worked',
+                        'byte_thing' => 0x01,
+                        'i32_thing' => pow(2, 30),
+                        'i64_thing' => pow(2, 60),
+                    )
+                ),
+                'expectedResult' => 4,
+            ];
+            yield 'nest_64Architecture' => [
+                'buffer' => '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":' . pow(2, 60) . '}}},"3":{"i32":32768}}}}',
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testNest_args::class,
+                'argsPropertyName' => 'thing',
+                'expectedValue' => new Xtruct2(
+                    array(
+                        'byte_thing' => 0x01,
+                        'struct_thing' => new Xtruct(
+                            array(
+                                'string_thing' => 'worked',
+                                'byte_thing' => 0x01,
+                                'i32_thing' => pow(2, 30),
+                                'i64_thing' => pow(2, 60),
+                            )
+                        ),
+                        'i32_thing' => pow(2, 15)
+                    )
+                ),
+                'expectedResult' => 6,
+            ];
+        } else {
+            yield 'i64_32Architecture' => [
+                'buffer' => '{"1":{"i64":1152921504606847000}}',
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testI64_args::class,
+                'argsPropertyName' => 'thing',
+                'expectedValue' => "1152921504606847000",
+                'expectedResult' => 1,
+            ];
+            yield 'struct_32Architecture' => [
+                'buffer' => '{"1":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}}}',
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testStruct_args::class,
+                'expectedValue' => new Xtruct(
+                    array(
+                        'string_thing' => 'worked',
+                        'byte_thing' => 0x01,
+                        'i32_thing' => pow(2, 30),
+                        'i64_thing' => "1152921504606847000",
+                    )
+                ),
+                'expectedResult' => 4,
+            ];
+            yield 'nest_32Architecture' => [
+                'buffer' => '{"1":{"rec":{"1":{"i8":1},"2":{"rec":{"1":{"str":"worked"},"4":{"i8":1},"9":{"i32":1073741824},"11":{"i64":1152921504606847000}}},"3":{"i32":32768}}}}',
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testNest_args::class,
+                'argsPropertyName' => 'thing',
+                'expectedValue' => new Xtruct2(
+                    array(
+                        'byte_thing' => 0x01,
+                        'struct_thing' => new Xtruct(
+                            array(
+                                'string_thing' => 'worked',
+                                'byte_thing' => 0x01,
+                                'i32_thing' => pow(2, 30),
+                                'i64_thing' => "1152921504606847000",
+                            )
+                        ),
+                        'i32_thing' => pow(2, 15)
+                    )
+                ),
+                'expectedResult' => 6,
+            ];
+        }
+        yield 'map' => [
+            'buffer' => '{"1":{"map":["i32","i32",3,{"7":77,"8":88,"9":99}]}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testMap_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => [
+                7 => 77,
+                8 => 88,
+                9 => 99
+            ],
+            'expectedResult' => 6,
+        ];
+        yield 'stringMap' => [
+            'buffer' => '{"1":{"map":["str","str",6,{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}]}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testStringMap_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => [
+                "a" => "123",
+                "a b" => "with spaces ",
+                "same" => "same",
+                "0" => "numeric key",
+                "longValue" => "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語",
+                "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語" => "long key"
+            ],
+            'expectedResult' => 12,
+        ];
+        yield 'set' => [
+            'buffer' => '{"1":{"set":["i32",3,1,5,6]}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testSet_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => [1 => true, 5 => true, 6 => true],
+            'expectedResult' => 4,
+        ];
+        yield 'list' => [
+            'buffer' => '{"1":{"lst":["i32",3,1,2,3]}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testList_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => [1, 2, 3],
+            'expectedResult' => 4,
+        ];
+        yield 'enum' => [
+            'buffer' => '{"1":{"i32":6}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testEnum_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => Numberz::SIX,
+            'expectedResult' => 1,
+        ];
+        yield 'typedef' => [
+            'buffer' => '{"1":{"i64":69}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testTypedef_args::class,
+            'argsPropertyName' => 'thing',
+            'expectedValue' => 69,
+            'expectedResult' => 1,
+        ];
+        yield 'mapmap' => [
+            'buffer' => '{"0":{"map":["i32","map",2,{"4":["i32","i32",4,{"1":1,"2":2,"3":3,"4":4}],"-4":["i32","i32",4,{"-4":-4,"-3":-3,"-2":-2,"-1":-1}]}]}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testMapMap_result::class,
+            'argsPropertyName' => 'success',
+            'expectedValue' => [
+                4 => [
+                    1 => 1,
+                    2 => 2,
+                    3 => 3,
+                    4 => 4,
+                ],
+                -4 => [
+                    -4 => -4,
+                    -3 => -3,
+                    -2 => -2,
+                    -1 => -1
+                ]
+            ],
+            'expectedResult' => 18,
+        ];
+
+        $xtruct1 = new Xtruct(
+            [
+                'string_thing' => 'Goodbye4',
+                'byte_thing' => 4,
+                'i32_thing' => 4,
+                'i64_thing' => 4,
+            ]
+        );
+
+        $xtruct2 = new Xtruct(
+            [
+                'string_thing' => 'Hello2',
+                'byte_thing' => 2,
+                'i32_thing' => 2,
+                'i64_thing' => 2,
+            ]
+        );
+
+        $userMap = [Numberz::FIVE => 5, Numberz::EIGHT => 8];
+
+        $insanity2 = new Insanity(
+            [
+                'userMap' => $userMap,
+                'xtructs' => [$xtruct1, $xtruct2],
+            ]
+        );
+
+        $insanity3 = $insanity2;
+
+        $insanity6 =
+            new Insanity(
+                [
+                    'userMap' => null,
+                    'xtructs' => null,
+                ]
+            );
+        yield 'insanity' => [
+            'buffer' => '{"0":{"map":["i64","map",2,{"1":["i32","rec",2,{"2":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}},"3":{"1":{"map":["i32","i64",2,{"5":5,"8":8}]},"2":{"lst":["rec",2,{"1":{"str":"Goodbye4"},"4":{"i8":4},"9":{"i32":4},"11":{"i64":4}},{"1":{"str":"Hello2"},"4":{"i8":2},"9":{"i32":2},"11":{"i64":2}}]}}}],"2":["i32","rec",1,{"6":{}}]}]}}',
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testInsanity_result::class,
+            'argsPropertyName' => 'success',
+            'expectedValue' => [
+                "1" => [
+                    Numberz::TWO => $insanity2,
+                    Numberz::THREE => $insanity3,
+                ],
+                "2" => [
+                    Numberz::SIX => $insanity6,
+                ],
+            ],
+            'expectedResult' => 31,
+        ];
+    }
+}
diff --git a/lib/php/test/Integration/Lib/Protocol/TSimpleJSONProtocolTest.php b/lib/php/test/Integration/Lib/Protocol/TSimpleJSONProtocolTest.php
new file mode 100644
index 0000000..e108ffc
--- /dev/null
+++ b/lib/php/test/Integration/Lib/Protocol/TSimpleJSONProtocolTest.php
@@ -0,0 +1,319 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Test\Thrift\Integration\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Protocol\TJSONProtocol;
+use Thrift\Protocol\TSimpleJSONProtocol;
+use Thrift\Transport\TMemoryBuffer;
+use Basic\ThriftTest\Xtruct;
+use Basic\ThriftTest\Xtruct2;
+
+/***
+ * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:nsglobal="Basic" -r  --out ./Resources/packages/php ./Resources/ThriftTest.thrift
+ */
+class TSimpleJSONProtocolTest extends TestCase
+{
+    private const BUFFER_SIZE = 8192; //big enough to read biggest serialized Fixture arg.
+
+    private $transport;
+    private $protocol;
+
+    public static function setUpBeforeClass(): void
+    {
+        if (!is_dir(__DIR__ . '/../../../Resources/packages/php')) {
+            self::fail(
+                'Before running Integration test suite, you must run the Thrift compiler against the ThriftTest.thrift file in the ./Resources directory.'
+            );
+        }
+    }
+
+    public function setUp(): void
+    {
+        $this->transport = new TMemoryBuffer();
+        $this->protocol = new TSimpleJSONProtocol($this->transport);
+        $this->transport->open();
+    }
+
+    public function testMessageWrite()
+    {
+        $input = new TJSONProtocol(new TMemoryBuffer('[1,"testString",1,0,{"0":{"str":"successResponse"}}]'));
+        $service = new \Basic\ThriftTest\ThriftTestClient($input, $this->protocol);
+        $result = $service->testString('test');
+        $this->assertSame('successResponse', $result);
+        $this->assertSame('["testString",1,0,{"thing":"test"}]', $this->protocol->getTransport()->getBuffer());
+    }
+
+    /**
+     * @dataProvider writeDataProvider
+     */
+    public function testWrite(
+        $argsClassName,
+        $argsValues,
+        $expected
+    ) {
+        $args = new $argsClassName($argsValues);
+        $args->write($this->protocol);
+
+        $actual = $this->transport->read(self::BUFFER_SIZE);
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function writeDataProvider()
+    {
+        if (!is_dir(__DIR__ . '/../../../Resources/packages/php')) {
+            throw new \RuntimeException(
+                'Before running Integration test suite, you must run the Thrift compiler against the ThriftTest.thrift file in the ./Resources directory.'
+            );
+        }
+
+        yield 'void' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testVoid_args::class,
+            'argsValues' => [],
+            'expected' => '{}',
+        ];
+        yield 'bool true' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testBool_args::class,
+            'argsValues' => [
+                'thing' => true,
+            ],
+            'expected' => '{"thing":1}',
+        ];
+        yield 'bool false' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testBool_args::class,
+            'argsValues' => [
+                'thing' => false,
+            ],
+            'expected' => '{"thing":0}',
+        ];
+        yield 'string1' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語",
+            ],
+            'expected' => '{"thing":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e"}',
+        ];
+        yield 'string2' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "quote: \\\" backslash:" .
+                    " forwardslash-escaped: \\/ " .
+                    " backspace: \b formfeed: \f newline: \n return: \r tab: " .
+                    " now-all-of-them-together: \"\\\/\b\n\r\t" .
+                    " now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><",
+            ],
+            'expected' => '{"thing":"quote: \\\\\" backslash: forwardslash-escaped: \\\\\/  backspace: \\\\b formfeed: \f newline: \n return: \r tab:  now-all-of-them-together: \"\\\\\\\\\/\\\\b\n\r\t now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"}',
+        ];
+
+        yield 'string3' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "string that ends in double-backslash \\\\",
+            ],
+            'expected' => '{"thing":"string that ends in double-backslash \\\\\\\\"}',
+        ];
+        yield 'string4 testUnicodeStringWithNonBMP' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testString_args::class,
+            'argsValues' => [
+                'thing' => "สวัสดี/𝒯",
+            ],
+            'expected' => '{"thing":"\u0e2a\u0e27\u0e31\u0e2a\u0e14\u0e35\/\ud835\udcaf"}',
+        ];
+        yield 'double' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsValues' => [
+                'thing' => 3.1415926535898,
+            ],
+            'expected' => '{"thing":3.1415926535898}',
+        ];
+        #TODO Should be fixed in future
+        yield 'double Nan' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsValues' => [
+                'thing' => NAN,
+            ],
+            'expected' => '{"thing":}',
+        ];
+        #TODO Should be fixed in future
+        yield 'double Infinity' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testDouble_args::class,
+            'argsValues' => [
+                'thing' => INF,
+            ],
+            'expected' => '{"thing":}',
+        ];
+        yield 'byte' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testByte_args::class,
+            'argsValues' => [
+                'thing' => 0x01,
+            ],
+            'expected' => '{"thing":1}',
+        ];
+        yield 'i32' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testI32_args::class,
+            'argsValues' => [
+                'thing' => pow(2, 30),
+            ],
+            'expected' => '{"thing":1073741824}',
+        ];
+        if (PHP_INT_SIZE == 8) {
+            yield 'i64_64Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testI64_args::class,
+                'argsValues' => [
+                    'thing' => pow(2, 60),
+                ],
+                'expected' => '{"thing":' . pow(2, 60) . '}',
+            ];
+            yield 'struct_64Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testStruct_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct(
+                        [
+                            'string_thing' => 'worked',
+                            'byte_thing' => 0x01,
+                            'i32_thing' => pow(2, 30),
+                            'i64_thing' => pow(2, 60),
+                        ]
+                    ),
+                ],
+                'expected' => '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '}}',
+            ];
+            yield 'nest_64Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testNest_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct2(
+                        [
+                            'byte_thing' => 0x01,
+                            'struct_thing' => new Xtruct(
+                                [
+                                    'string_thing' => 'worked',
+                                    'byte_thing' => 0x01,
+                                    'i32_thing' => pow(2, 30),
+                                    'i64_thing' => pow(2, 60),
+                                ]
+                            ),
+                            'i32_thing' => pow(2, 15),
+                        ]
+                    ),
+                ],
+                'expected' => '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":' . pow(2, 60) . '},"i32_thing":32768}}',
+            ];
+        } else {
+            yield 'i64_32Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testI64_args::class,
+                'argsValues' => [
+                    'thing' => "1152921504606847000",
+                ],
+                'expected' => '{"thing":1152921504606847000}',
+            ];
+            yield 'struct_32Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testStruct_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct(
+                        [
+                            'string_thing' => 'worked',
+                            'byte_thing' => 0x01,
+                            'i32_thing' => pow(2, 30),
+                            'i64_thing' => pow(2, 60),
+                        ]
+                    ),
+                ],
+                'expected' => '{"thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000}}',
+            ];
+            yield 'nest_32Architecture' => [
+                'argsClassName' => \Basic\ThriftTest\ThriftTest_testNest_args::class,
+                'argsValues' => [
+                    'thing' => new Xtruct2(
+                        [
+                            'byte_thing' => 0x01,
+                            'struct_thing' => new Xtruct(
+                                [
+                                    'string_thing' => 'worked',
+                                    'byte_thing' => 0x01,
+                                    'i32_thing' => pow(2, 30),
+                                    'i64_thing' => '1152921504606847000',
+                                ]
+                            ),
+                            'i32_thing' => pow(2, 15),
+                        ]
+                    ),
+                ],
+                'expected' => '{"thing":{"byte_thing":1,"struct_thing":{"string_thing":"worked","byte_thing":1,"i32_thing":1073741824,"i64_thing":1152921504606847000},"i32_thing":32768}}',
+            ];
+        }
+        yield 'map' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testMap_args::class,
+            'argsValues' => [
+                'thing' => [
+                    7 => 77,
+                    8 => 88,
+                    9 => 99,
+                ],
+            ],
+            'expected' => '{"thing":{"7":77,"8":88,"9":99}}',
+        ];
+        yield 'stringMap' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testStringMap_args::class,
+            'argsValues' => [
+                'thing' => [
+                    "a" => "123",
+                    "a b" => "with spaces ",
+                    "same" => "same",
+                    "0" => "numeric key",
+                    "longValue" => "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語",
+                    "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語" => "long key"
+                ],
+            ],
+            'expected' => '{"thing":{"a":"123","a b":"with spaces ","same":"same","0":"numeric key","longValue":"Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e","Afrikaans, Alemannisch, Aragon\u00e9s, \u0627\u0644\u0639\u0631\u0628\u064a\u0629, \u0645\u0635\u0631\u0649, Asturianu, Aymar aru, Az\u0259rbaycan, \u0411\u0430\u0448\u04a1\u043e\u0440\u0442, Boarisch, \u017demait\u0117\u0161ka, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f, \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f (\u0442\u0430\u0440\u0430\u0448\u043a\u0435\u0432\u0456\u0446\u0430), \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438, Bamanankan, \u09ac\u09be\u0982\u09b2\u09be, Brezhoneg, Bosanski, Catal\u00e0, M\u00ecng-d\u0115\u0324ng-ng\u1e73\u0304, \u041d\u043e\u0445\u0447\u0438\u0439\u043d, Cebuano, \u13e3\u13b3\u13a9, \u010cesky, \u0421\u043b\u043e\u0432\u0463\u0301\u043d\u044c\u0441\u043a\u044a \/ \u2c14\u2c0e\u2c11\u2c02\u2c21\u2c10\u2c20\u2c14\u2c0d\u2c1f, \u0427\u04d1\u0432\u0430\u0448\u043b\u0430, Cymraeg, Dansk, Zazaki, \u078b\u07a8\u0788\u07ac\u0780\u07a8\u0784\u07a6\u0790\u07b0, \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac, Emili\u00e0n e rumagn\u00f2l, English, Esperanto, Espa\u00f1ol, Eesti, Euskara, \u0641\u0627\u0631\u0633\u06cc, Suomi, V\u00f5ro, F\u00f8royskt, Fran\u00e7ais, Arpetan, Furlan, Frysk, Gaeilge, \u8d1b\u8a9e, G\u00e0idhlig, Galego, Ava\u00f1e\'\u1ebd, \u0a97\u0ac1\u0a9c\u0ab0\u0abe\u0aa4\u0ac0, Gaelg, \u05e2\u05d1\u05e8\u05d9\u05ea, \u0939\u093f\u0928\u094d\u0926\u0940, Fiji Hindi, Hrvatski, Krey\u00f2l ayisyen, Magyar, \u0540\u0561\u0575\u0565\u0580\u0565\u0576, Interlingua, Bahasa Indonesia, Ilokano, Ido, \u00cdslenska, Italiano, \u65e5\u672c\u8a9e, Lojban, Basa Jawa, \u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8, Kongo, Kalaallisut, \u0c95\u0ca8\u0ccd\u0ca8\u0ca1, \ud55c\uad6d\uc5b4, \u041a\u044a\u0430\u0440\u0430\u0447\u0430\u0439-\u041c\u0430\u043b\u043a\u044a\u0430\u0440, Ripoarisch, Kurd\u00ee, \u041a\u043e\u043c\u0438, Kernewek, \u041a\u044b\u0440\u0433\u044b\u0437\u0447\u0430, Latina, Ladino, L\u00ebtzebuergesch, Limburgs, Ling\u00e1la, \u0ea5\u0eb2\u0ea7, Lietuvi\u0173, Latvie\u0161u, Basa Banyumasan, Malagasy, \u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438, \u0d2e\u0d32\u0d2f\u0d3e\u0d33\u0d02, \u092e\u0930\u093e\u0920\u0940, Bahasa Melayu, \u0645\u0627\u0632\u0650\u0631\u0648\u0646\u06cc, Nnapulitano, Nedersaksisch, \u0928\u0947\u092a\u093e\u0932 \u092d\u093e\u0937\u093e, Nederlands, \u202aNorsk (nynorsk)\u202c, \u202aNorsk (bokm\u00e5l)\u202c, Nouormand, Din\u00e9 bizaad, Occitan, \u0418\u0440\u043e\u043d\u0430\u0443, Papiamentu, Deitsch, Norfuk \/ Pitkern, Polski, \u067e\u0646\u062c\u0627\u0628\u06cc, \u067e\u069a\u062a\u0648, Portugu\u00eas, Runa Simi, Rumantsch, Romani, Rom\u00e2n\u0103, \u0420\u0443\u0441\u0441\u043a\u0438\u0439, \u0421\u0430\u0445\u0430 \u0442\u044b\u043b\u0430, Sardu, Sicilianu, Scots, S\u00e1megiella, Simple English, Sloven\u010dina, Sloven\u0161\u010dina, \u0421\u0440\u043f\u0441\u043a\u0438 \/ Srpski, Seeltersk, Svenska, Kiswahili, \u0ba4\u0bae\u0bbf\u0bb4\u0bcd, \u0c24\u0c46\u0c32\u0c41\u0c17\u0c41, \u0422\u043e\u04b7\u0438\u043a\u04e3, \u0e44\u0e17\u0e22, T\u00fcrkmen\u00e7e, Tagalog, T\u00fcrk\u00e7e, \u0422\u0430\u0442\u0430\u0440\u0447\u0430\/Tatar\u00e7a, \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430, \u0627\u0631\u062f\u0648, Ti\u1ebfng Vi\u1ec7t, Volap\u00fck, Walon, Winaray, \u5434\u8bed, isiXhosa, \u05d9\u05d9\u05b4\u05d3\u05d9\u05e9, Yor\u00f9b\u00e1, Ze\u00eauws, \u4e2d\u6587, B\u00e2n-l\u00e2m-g\u00fa, \u7cb5\u8a9e":"long key"}}',
+        ];
+        yield 'set' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testSet_args::class,
+            'argsValues' => [
+                'thing' => [1 => true, 5 => true, 6 => true],
+            ],
+            'expected' => '{"thing":[1,5,6]}',
+        ];
+        yield 'list' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testList_args::class,
+            'argsValues' => [
+                'thing' => [1, 2, 3],
+            ],
+            'expected' => '{"thing":[1,2,3]}',
+        ];
+        yield 'enum' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testEnum_args::class,
+            'argsValues' => [
+                'thing' => \Basic\ThriftTest\Numberz::SIX,
+            ],
+            'expected' => '{"thing":6}',
+        ];
+        yield 'typedef' => [
+            'argsClassName' => \Basic\ThriftTest\ThriftTest_testTypedef_args::class,
+            'argsValues' => [
+                'thing' => 69,
+            ],
+            'expected' => '{"thing":69}',
+        ];
+    }
+}
diff --git a/lib/php/test/Unit/BinarySerializerTest.php b/lib/php/test/Integration/Lib/Serializer/BinarySerializerTest.php
similarity index 66%
rename from lib/php/test/Unit/BinarySerializerTest.php
rename to lib/php/test/Integration/Lib/Serializer/BinarySerializerTest.php
index 744ca7a..44eef93 100644
--- a/lib/php/test/Unit/BinarySerializerTest.php
+++ b/lib/php/test/Integration/Lib/Serializer/BinarySerializerTest.php
@@ -19,35 +19,26 @@
  * under the License.
  */
 
-namespace Test\Thrift\Unit;
+namespace Test\Thrift\Integration\Lib\Serializer;
 
 use PHPUnit\Framework\TestCase;
-use Thrift\ClassLoader\ThriftClassLoader;
 use Thrift\Serializer\TBinarySerializer;
 
 /***
  * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r  --out ./Resources/packages/php ./Resources/ThriftTest.thrift
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:nsglobal="Basic" -r  --out ./Resources/packages/php ./Resources/ThriftTest.thrift
  */
 class BinarySerializerTest extends TestCase
 {
-    public function setUp(): void
-    {
-        $loader = new ThriftClassLoader();
-        $loader->registerNamespace('ThriftTest', __DIR__ . '/../Resources/packages/php');
-        $loader->registerDefinition('ThriftTest', __DIR__ . '/../Resources/packages/php');
-        $loader->register();
-    }
-
     /**
      * We try to serialize and deserialize a random object to make sure no exceptions are thrown.
      * @see THRIFT-1579
      */
     public function testBinarySerializer()
     {
-        $struct = new \ThriftTest\Xtruct(array('string_thing' => 'abc'));
-        $serialized = TBinarySerializer::serialize($struct, 'ThriftTest\\Xtruct');
-        $deserialized = TBinarySerializer::deserialize($serialized, 'ThriftTest\\Xtruct');
+        $struct = new \Basic\ThriftTest\Xtruct(array('string_thing' => 'abc'));
+        $serialized = TBinarySerializer::serialize($struct, '\\Basic\\ThriftTest\\Xtruct');
+        $deserialized = TBinarySerializer::deserialize($serialized, '\\Basic\\ThriftTest\\Xtruct');
         $this->assertEquals($struct, $deserialized);
     }
 }
diff --git a/lib/php/test/Unit/JsonSerializeTest.php b/lib/php/test/Integration/Lib/Serializer/JsonSerializeTest.php
similarity index 71%
rename from lib/php/test/Unit/JsonSerializeTest.php
rename to lib/php/test/Integration/Lib/Serializer/JsonSerializeTest.php
index 66e4d5e..d3fe3f7 100644
--- a/lib/php/test/Unit/JsonSerializeTest.php
+++ b/lib/php/test/Integration/Lib/Serializer/JsonSerializeTest.php
@@ -19,7 +19,7 @@
  * under the License.
  */
 
-namespace Test\Thrift\Unit;
+namespace Test\Thrift\Integration\Lib\Serializer;
 
 use PHPUnit\Framework\TestCase;
 use stdClass;
@@ -27,21 +27,13 @@
 
 /***
  * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php:json -r  --out ./Resources/packages/phpjs ./Resources/ThriftTest.thrift
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:json,nsglobal="Json" -r  --out ./Resources/packages/phpjs ./Resources/ThriftTest.thrift
  */
 class JsonSerializeTest extends TestCase
 {
-    protected function setUp(): void
-    {
-        $loader = new ThriftClassLoader();
-        $loader->registerNamespace('ThriftTest', __DIR__ . '/../Resources/packages/phpjs');
-        $loader->registerDefinition('ThriftTest', __DIR__ . '/../Resources/packages/phpjs');
-        $loader->register();
-    }
-
     public function testEmptyStruct()
     {
-        $empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar'));
+        $empty = new \Json\ThriftTest\EmptyStruct(array('non_existing_key' => 'bar'));
         $this->assertEquals(new stdClass(), json_decode(json_encode($empty)));
     }
 
@@ -51,7 +43,7 @@
             'string_thing' => 'foo',
             'i64_thing' => 1234567890,
         );
-        $xtruct = new \ThriftTest\Xtruct($input);
+        $xtruct = new \Json\ThriftTest\Xtruct($input);
 
         // Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here!
         $expected = new stdClass();
@@ -62,9 +54,9 @@
 
     public function testNestedStructs()
     {
-        $xtruct2 = new \ThriftTest\Xtruct2(array(
+        $xtruct2 = new \Json\ThriftTest\Xtruct2(array(
             'byte_thing' => 42,
-            'struct_thing' => new \ThriftTest\Xtruct(array(
+            'struct_thing' => new \Json\ThriftTest\Xtruct(array(
                 'i32_thing' => 123456,
             )),
         ));
@@ -79,8 +71,8 @@
     public function testInsanity()
     {
         $xinput = array('string_thing' => 'foo');
-        $xtruct = new \ThriftTest\Xtruct($xinput);
-        $insanity = new \ThriftTest\Insanity(array(
+        $xtruct = new \Json\ThriftTest\Xtruct($xinput);
+        $insanity = new \Json\ThriftTest\Insanity(array(
             'xtructs' => array($xtruct, $xtruct, $xtruct)
         ));
         $expected = new stdClass();
@@ -90,8 +82,8 @@
 
     public function testNestedLists()
     {
-        $bonk = new \ThriftTest\Bonk(array('message' => 'foo'));
-        $nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk)))));
+        $bonk = new \Json\ThriftTest\Bonk(array('message' => 'foo'));
+        $nested = new \Json\ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk)))));
         $expected = new stdClass();
         $expected->bonk = array(array(array((object)array('message' => 'foo'))));
         $this->assertEquals($expected, json_decode(json_encode($nested)));
@@ -99,17 +91,17 @@
 
     public function testMaps()
     {
-        $intmap = new \ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]);
-        $emptymap = new \ThriftTest\ThriftTest_testMap_args([]);
+        $intmap = new \Json\ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]);
+        $emptymap = new \Json\ThriftTest\ThriftTest_testMap_args([]);
         $this->assertEquals('{"thing":{"0":"zero"}}', json_encode($intmap));
         $this->assertEquals('{}', json_encode($emptymap));
     }
 
     public function testScalarTypes()
     {
-        $b = new \ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']);
+        $b = new \Json\ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']);
         $this->assertEquals('{"im_true":true,"im_false":false}', json_encode($b));
-        $s = new \ThriftTest\StructA(['s' => 42]);
+        $s = new \Json\ThriftTest\StructA(['s' => 42]);
         $this->assertEquals('{"s":"42"}', json_encode($s));
     }
 }
diff --git a/lib/php/test/Integration/ValidatorOopTest.php b/lib/php/test/Integration/ValidatorOopTest.php
new file mode 100644
index 0000000..c3dce03
--- /dev/null
+++ b/lib/php/test/Integration/ValidatorOopTest.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace Test\Thrift\Integration;
+
+/***
+ * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:validate,oop,nsglobal="ValidateOop" -r --out ./Resources/packages/phpvo ./Resources/ThriftTest.thrift
+ */
+class ValidatorOopTest extends BaseValidatorTest
+{
+    public function getNsGlobal()
+    {
+        return 'ValidateOop';
+    }
+}
diff --git a/lib/php/test/Unit/ValidatorTest.php b/lib/php/test/Integration/ValidatorTest.php
similarity index 62%
rename from lib/php/test/Unit/ValidatorTest.php
rename to lib/php/test/Integration/ValidatorTest.php
index b125424..0d6a697 100644
--- a/lib/php/test/Unit/ValidatorTest.php
+++ b/lib/php/test/Integration/ValidatorTest.php
@@ -19,23 +19,16 @@
  * under the License.
  */
 
-namespace Test\Thrift\Unit;
-
-use Thrift\ClassLoader\ThriftClassLoader;
+namespace Test\Thrift\Integration;
 
 /***
  * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php:validate -r  --out ./Resources/packages/phpv ./Resources/ThriftTest.thrift
+ * lib/php/test$ ../../../compiler/cpp/thrift --gen php:validate,nsglobal="Validate" -r  --out ./Resources/packages/phpv ./Resources/ThriftTest.thrift
  */
 class ValidatorTest extends BaseValidatorTest
 {
-    public function setUp(): void
+    public function getNsGlobal()
     {
-        $loader = new ThriftClassLoader();
-        $loader->registerNamespace('ThriftTest', __DIR__ . '/../Resources/packages/phpv');
-        $loader->registerDefinition('ThriftTest', __DIR__ . '/../Resources/packages/phpv');
-        $loader->registerNamespace('TestValidators', __DIR__ . '/../Resources/packages/phpv');
-        $loader->registerDefinition('TestValidators', __DIR__ . '/../Resources/packages/phpv');
-        $loader->register();
+        return 'Validate';
     }
 }
diff --git a/lib/php/test/Makefile.am b/lib/php/test/Makefile.am
index 1e534ca..b6a5325 100644
--- a/lib/php/test/Makefile.am
+++ b/lib/php/test/Makefile.am
@@ -25,11 +25,11 @@
 	mkdir -p ./Resources/packages/phpvo
 	mkdir -p ./Resources/packages/phpjs
 	mkdir -p ./Resources/packages/phpcm
-	$(THRIFT) --gen php -r --out ./Resources/packages/php Resources/ThriftTest.thrift
-	$(THRIFT) --gen php:validate -r --out ./Resources/packages/phpv Resources/ThriftTest.thrift
-	$(THRIFT) --gen php:validate,oop -r --out ./Resources/packages/phpvo Resources/ThriftTest.thrift
-	$(THRIFT) --gen php:json -r --out ./Resources/packages/phpjs Resources/ThriftTest.thrift
-	$(THRIFT) --gen php:classmap,server,rest -r --out ./Resources/packages/phpcm Resources/ThriftTest.thrift
+	$(THRIFT) --gen php:nsglobal="Basic" -r --out ./Resources/packages/php Resources/ThriftTest.thrift
+	$(THRIFT) --gen php:validate,nsglobal="Validate" -r --out ./Resources/packages/phpv Resources/ThriftTest.thrift
+	$(THRIFT) --gen php:validate,oop,nsglobal="ValidateOop" -r --out ./Resources/packages/phpvo Resources/ThriftTest.thrift
+	$(THRIFT) --gen php:json,nsglobal="Json" -r --out ./Resources/packages/phpjs Resources/ThriftTest.thrift
+	$(THRIFT) --gen php:classmap,server,rest,nsglobal="Classmap" -r --out ./Resources/packages/phpcm Resources/ThriftTest.thrift
 
 deps: $(top_srcdir)/composer.json
 	composer install --working-dir=$(top_srcdir)
diff --git a/lib/php/test/Unit/Lib/ClassLoader/ThriftClassLoaderTest.php b/lib/php/test/Unit/Lib/ClassLoader/ThriftClassLoaderTest.php
index 46ed2ec..d99edfa 100644
--- a/lib/php/test/Unit/Lib/ClassLoader/ThriftClassLoaderTest.php
+++ b/lib/php/test/Unit/Lib/ClassLoader/ThriftClassLoaderTest.php
@@ -25,10 +25,6 @@
 use PHPUnit\Framework\TestCase;
 use Thrift\ClassLoader\ThriftClassLoader;
 
-/***
- * This test depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php:classmap,server,rest -r  --out ./Resources/packages/phpcm ./Resources/ThriftTest.thrift
- */
 class ThriftClassLoaderTest extends TestCase
 {
     use PHPMock;
@@ -111,108 +107,4 @@
             'apcuPrefix' => 'APCU_PREFIX',
         ];
     }
-
-    /**
-     * @dataProvider registerDefinitionDataProvider
-     */
-    public function testRegisterDefinition(
-        $definitions,
-        $class,
-        $checkInterfaceExist = false,
-        $useApcu = false,
-        $apcuPrefix = null
-    ) {
-        $this->getFunctionMock('Thrift\ClassLoader', 'apcu_fetch')
-             ->expects($useApcu ? $this->once() : $this->never())
-             ->with($apcuPrefix . $class)
-             ->willReturn(false);
-
-        $this->getFunctionMock('Thrift\ClassLoader', 'apcu_store')
-            ->expects($useApcu ? $this->once() : $this->never())
-             ->with($apcuPrefix . $class, $this->anything())
-             ->willReturn(true);
-
-        $loader = new ThriftClassLoader($useApcu, $apcuPrefix);
-        foreach ($definitions as $namespace => $paths) {
-            $loader->registerDefinition($namespace, $paths);
-        }
-        $loader->register();
-
-        $loader->loadClass($class);
-        if ($checkInterfaceExist) {
-            $this->assertTrue(interface_exists($class, false), "->loadClass() loads '$class'");
-        } else {
-            $this->assertTrue(class_exists($class, false), "->loadClass() loads '$class'");
-        }
-    }
-
-    public function registerDefinitionDataProvider()
-    {
-        yield 'loadType' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => 'ThriftTest\Xtruct',
-        ];
-        yield 'loadInterface' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => '\ThriftTest\ThriftTestIf',
-            'checkInterfaceExist' => true,
-        ];
-        yield 'loadClient' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => '\ThriftTest\ThriftTestClient',
-        ];
-        yield 'loadProcessor' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => '\ThriftTest\ThriftTestProcessor',
-        ];
-        yield 'loadRest' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => '\ThriftTest\ThriftTestRest',
-        ];
-        yield 'load_args' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => '\ThriftTest\ThriftTest_testVoid_args',
-        ];
-        yield 'load_result' => [
-            'definitions' => [
-                'ThriftTest' => __DIR__ . '/../../../Resources/packages/phpcm',
-            ],
-            'class' => '\ThriftTest\ThriftTest_testVoid_result',
-        ];
-        yield 'pathAsArray' => [
-            'definitions' => [
-                'ThriftTest' => [__DIR__ . '/../../../Resources/packages/phpcm'],
-            ],
-            'class' => 'ThriftTest\Xtruct',
-        ];
-        yield 'severalDefinitions' => [
-            'definitions' => [
-                'ThriftTest' => [__DIR__ . '/../../../Resources/packages/phpcm'],
-                'TestValidators' => [__DIR__ . '/../../../Resources/packages/phpcm'],
-            ],
-            'class' => '\TestValidators\TestServiceClient',
-        ];
-        yield 'useApcu' => [
-            'definitions' => [
-                'ThriftTest' => [__DIR__ . '/../../../Resources/packages/phpcm'],
-                'TestValidators' => [__DIR__ . '/../../../Resources/packages/phpcm'],
-            ],
-            'class' => '\TestValidators\TestServiceClient',
-            'checkInterfaceExist' => false,
-            'useApcu' => true,
-            'apcuPrefix' => 'APCU_PREFIX',
-        ];
-    }
 }
diff --git a/lib/php/test/Unit/Lib/Protocol/TBinaryProtocolAcceleratedTest.php b/lib/php/test/Unit/Lib/Protocol/TBinaryProtocolAcceleratedTest.php
new file mode 100644
index 0000000..4a82a5a
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Protocol/TBinaryProtocolAcceleratedTest.php
@@ -0,0 +1,73 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Protocol\TBinaryProtocolAccelerated;
+use Thrift\Transport\TBufferedTransport;
+use Thrift\Transport\TMemoryBuffer;
+use Thrift\Transport\TSocket;
+
+class TBinaryProtocolAcceleratedTest extends TestCase
+{
+    /**
+     * @dataProvider constructDataProvider
+     */
+    public function testConstruct(
+        $transport,
+        $expectedTransport
+    ) {
+        $protocol = new TBinaryProtocolAccelerated($transport);
+        $this->assertInstanceOf($expectedTransport, $protocol->getTransport());
+    }
+
+    public function constructDataProvider()
+    {
+        yield 'not buffered transport' => [
+            'transport' => new TMemoryBuffer(),
+            'expectedTransport' => TMemoryBuffer::class,
+        ];
+        yield 'buffered transport' => [
+            'transport' => new TSocket(),
+            'expectedTransport' => TBufferedTransport::class,
+        ];
+    }
+
+    /**
+     * @dataProvider strictParamsDataProvider
+     */
+    public function testStrictParams($strictRead, $strictWrite)
+    {
+        $protocol = new TBinaryProtocolAccelerated(new TMemoryBuffer(), $strictRead, $strictWrite);
+        $this->assertEquals($strictRead, $protocol->isStrictRead());
+        $this->assertEquals($strictWrite, $protocol->isStrictWrite());
+    }
+
+    public function strictParamsDataProvider()
+    {
+        yield 'strict read and write' => [true, true];
+        yield 'not strict read and write' => [false, false];
+        yield 'strict read and not strict write' => [true, false];
+        yield 'not strict read and strict write' => [false, true];
+    }
+}
diff --git a/lib/php/test/Unit/Lib/Protocol/TBinaryProtocolTest.php b/lib/php/test/Unit/Lib/Protocol/TBinaryProtocolTest.php
new file mode 100644
index 0000000..2648b55
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Protocol/TBinaryProtocolTest.php
@@ -0,0 +1,1009 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Exception\TProtocolException;
+use Thrift\Protocol\TBinaryProtocol;
+use Thrift\Transport\TTransport;
+use Thrift\Type\TType;
+
+class TBinaryProtocolTest extends TestCase
+{
+    private const VERSION_MASK = 0xffff0000;
+    private const VERSION_1 = 0x80010000;
+
+    /**
+     * @dataProvider writeMessageBeginDataProvider
+     */
+    public function testWriteMessageBegin(
+        $strictWrite,
+        $name,
+        $type,
+        $seqid,
+        $writeCallsParams,
+        $writeCallsResults,
+        $expectedResult
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, $strictWrite);
+
+        $transport->expects($this->exactly(count($writeCallsParams)))
+                  ->method('write')
+                  ->withConsecutive(...$writeCallsParams)
+                  ->willReturnOnConsecutiveCalls(...$writeCallsResults);
+
+        $result = $protocol->writeMessageBegin($name, $type, $seqid);
+        $this->assertEquals($expectedResult, $result);
+    }
+
+    public function writeMessageBeginDataProvider()
+    {
+        $type = TType::STRING;
+        $seqid = 555;
+
+        yield 'strictWrite=true' => [
+            'strictWrite' => true,
+            'name' => 'testName',
+            'type' => $type,
+            'seqid' => $seqid,
+            'writeCallsParams' => [
+                [pack('N', self::VERSION_1 | $type), 4], #writeI32
+                [pack('N', strlen('testName')), 4], #writeStringLen
+                ['testName', 8], #writeString
+                [pack('N', $seqid), 4], #writeI32
+            ],
+            'writeCallsResults' => [
+                4,
+                4,
+                8,
+                4,
+            ],
+            'expectedResult' => 20,
+        ];
+
+        yield 'strictWrite=false' => [
+            'strictWrite' => false,
+            'name' => 'testName',
+            'type' => $type,
+            'seqid' => $seqid,
+            'writeCallsParams' => [
+                [pack('N', strlen('testName')), 4], #writeStringLen
+                ['testName', 8], #writeString
+                [pack('c', $type), 1], #writeByte
+                [pack('N', $seqid), 4], #writeI32
+            ],
+            'writeCallsResults' => [
+                4,
+                8,
+                1,
+                4,
+            ],
+            'expectedResult' => 17,
+        ];
+    }
+
+    public function testWriteMessageEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeMessageEnd());
+    }
+
+    public function testWriteStructBegin()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeStructBegin('testName'));
+    }
+
+    public function testWriteStructEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeStructEnd());
+    }
+
+    public function testWriteFieldBegin()
+    {
+        $fieldName = 'testName';
+        $fieldType = TType::STRING;
+        $fieldId = 555;
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(2))
+            ->method('write')
+            ->withConsecutive(
+                ...[
+                       [pack('c', $fieldType), 1], #writeByte
+                       [pack('n', $fieldId), 2], #writeI16
+                   ]
+            )->willReturnOnConsecutiveCalls([1, 2]);
+
+        $this->assertEquals(3, $protocol->writeFieldBegin($fieldName, $fieldType, $fieldId));
+    }
+
+    public function testWriteFieldEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeFieldEnd());
+    }
+
+    public function testWriteFieldStop()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('c', TType::STOP), 1) #writeByte
+            ->willReturn(1);
+
+        $this->assertEquals(1, $protocol->writeFieldStop());
+    }
+
+    public function testWriteMapBegin()
+    {
+        $keyType = TType::I32;
+        $valType = TType::STRING;
+        $size = 99;
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(3))
+            ->method('write')
+            ->withConsecutive(
+                ...[
+                       [pack('c', $keyType), 1], #writeByte
+                       [pack('c', $valType), 1], #writeByte
+                       [pack('N', $size), 4], #writeI32
+                   ]
+            )->willReturnOnConsecutiveCalls([1, 1, 4]);
+
+        $this->assertEquals(6, $protocol->writeMapBegin($keyType, $valType, $size));
+    }
+
+    public function testWriteMapEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeMapEnd());
+    }
+
+    public function testWriteListBegin()
+    {
+        $elemType = TType::I32;
+        $size = 99;
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(2))
+            ->method('write')
+            ->withConsecutive(
+                ...[
+                       [pack('c', $elemType), 1], #writeByte
+                       [pack('N', $size), 4], #writeI32
+                   ]
+            )->willReturnOnConsecutiveCalls([1, 4]);
+
+        $this->assertEquals(5, $protocol->writeListBegin($elemType, $size));
+    }
+
+    public function testWriteListEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeListEnd());
+    }
+
+    public function testWriteSetBegin()
+    {
+        $elemType = TType::I32;
+        $size = 99;
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(2))
+            ->method('write')
+            ->withConsecutive(
+                ...[
+                       [pack('c', $elemType), 1], #writeByte
+                       [pack('N', $size), 4], #writeI32
+                   ]
+            )->willReturnOnConsecutiveCalls([1, 4]);
+
+        $this->assertEquals(5, $protocol->writeSetBegin($elemType, $size));
+    }
+
+    public function testWriteSetEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->writeSetEnd());
+    }
+
+    public function testWriteBool()
+    {
+        $value = true;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('c', (int)$value), 1) #writeByte
+            ->willReturn(1);
+
+        $this->assertEquals(1, $protocol->writeBool($value));
+    }
+
+    public function testWriteByte()
+    {
+        $value = 1;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('c', $value), 1) #writeByte
+            ->willReturn(1);
+
+        $this->assertEquals(1, $protocol->writeByte($value));
+    }
+
+    public function testWriteI16()
+    {
+        $value = 1;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('n', $value), 2) #writeI16
+            ->willReturn(2);
+
+        $this->assertEquals(2, $protocol->writeI16($value));
+    }
+
+    public function testWriteI32()
+    {
+        $value = 1;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('N', $value), 4) #writeI32
+            ->willReturn(4);
+
+        $this->assertEquals(4, $protocol->writeI32($value));
+    }
+
+    public function testWriteI64For32BitArchitecture()
+    {
+        if (PHP_INT_SIZE !== 4) {
+            $this->markTestSkipped('Test is only for 32 bit architecture');
+        }
+        $value = 1;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $neg = $value < 0;
+
+        if ($neg) {
+            $value *= -1;
+        }
+
+        $hi = (int)($value / 4294967296);
+        $lo = (int)$value;
+
+        if ($neg) {
+            $hi = ~$hi;
+            $lo = ~$lo;
+            if (($lo & (int)0xffffffff) == (int)0xffffffff) {
+                $lo = 0;
+                $hi++;
+            } else {
+                $lo++;
+            }
+        }
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('N2', $hi, $lo), 8) #writeI64
+            ->willReturn(4);
+
+        $this->assertEquals(8, $protocol->writeI64($value));
+    }
+
+    public function testWriteI64For64BitArchitecture()
+    {
+        if (PHP_INT_SIZE == 4) {
+            $this->markTestSkipped('Test is only for 64 bit architecture');
+        }
+        $value = 1;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $hi = $value >> 32;
+        $lo = $value & 0xFFFFFFFF;
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('N2', $hi, $lo), 8) #writeI64
+            ->willReturn(8);
+
+        $this->assertEquals(8, $protocol->writeI64($value));
+    }
+
+    public function testWriteDouble()
+    {
+        $value = 1;
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(strrev(pack('d', $value)), 8) #writeDouble
+            ->willReturn(8);
+
+        $this->assertEquals(8, $protocol->writeDouble($value));
+    }
+
+    public function testWriteString()
+    {
+        $value = 'string';
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(2))
+            ->method('write')
+            ->withConsecutive(
+                ...[
+                       [pack('N', strlen($value))], #writeI32,
+                       [$value, strlen($value)], #write,
+                   ]
+            )->willReturnOnConsecutiveCalls([4, 6]);
+
+        $this->assertEquals(10, $protocol->writeString($value));
+    }
+
+    /**
+     * @dataProvider readMessageBeginDataProvider
+     */
+    public function testReadMessageBegin(
+        $strictRead,
+        $readCallsParams,
+        $readCallsResults,
+        $expectedReadLengthResult,
+        $expectedName,
+        $expectedType,
+        $expectedSeqid,
+        $expectedException = null,
+        $expectedExceptionMessage = null,
+        $expectedExceptionCode = null
+    ) {
+        if ($expectedException) {
+            $this->expectException($expectedException);
+            $this->expectExceptionMessage($expectedExceptionMessage);
+            $this->expectExceptionCode($expectedExceptionCode);
+        }
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, $strictRead, true);
+
+        $transport->expects($this->exactly(count($readCallsParams)))
+                  ->method('readAll')
+                  ->withConsecutive(...$readCallsParams)
+                  ->willReturnOnConsecutiveCalls(...$readCallsResults);
+
+        $result = $protocol->readMessageBegin($name, $type, $seqid);
+        $this->assertEquals($expectedReadLengthResult, $result);
+        $this->assertEquals($expectedName, $name);
+        $this->assertEquals($expectedType, $type);
+        $this->assertEquals($expectedSeqid, $seqid);
+    }
+
+    public function readMessageBeginDataProvider()
+    {
+        yield 'strictRead=true' => [
+            'strictRead' => true,
+            'readCallsParams' => [
+                [4], #readI32
+                [4], #readStringLen
+                [8], #readString
+                [4], #readI32
+            ],
+            'readCallsResults' => [
+                pack('N', 0x80010000 | TType::STRING), #version
+                pack('N', strlen('testName')),
+                'testName',
+                pack('N', 555),
+            ],
+            'expectedReadLengthResult' => 20,
+            'expectedName' => 'testName',
+            'expectedType' => TType::STRING,
+            'expectedSeqid' => 555,
+        ];
+
+        yield 'incorrect version' => [
+            'strictRead' => true,
+            'readCallsParams' => [
+                [4], #readI32
+            ],
+            'readCallsResults' => [
+                pack('N', 0x80000000 | TType::STRING), #version
+            ],
+            'expectedReadLengthResult' => 4,
+            'expectedName' => '',
+            'expectedType' => 0,
+            'expectedSeqid' => 0,
+            'expectedException' => TProtocolException::class,
+            'expectedExceptionMessage' => 'Bad version identifier: -2147483637',
+            'expectedExceptionCode' => TProtocolException::BAD_VERSION,
+        ];
+
+        yield 'strictRead=false' => [
+            'strictRead' => false,
+            'readCallsParams' => [
+                [4], #readStringLen
+                [8], #readString
+                [1], #readByte
+                [4], #readI32
+            ],
+            'readCallsResults' => [
+                pack('N', strlen('testName')),
+                'testName',
+                pack('c', TType::STRING),
+                pack('N', 555),
+            ],
+            'expectedReadLengthResult' => 17,
+            'expectedName' => 'testName',
+            'expectedType' => TType::STRING,
+            'expectedSeqid' => 555,
+        ];
+
+        yield 'strictRead=true without version' => [
+            'strictRead' => true,
+            'readCallsParams' => [
+                [4], #readStringLen
+            ],
+            'readCallsResults' => [
+                pack('N', strlen('testName')),
+            ],
+            'expectedReadLengthResult' => 17,
+            'expectedName' => 'testName',
+            'expectedType' => TType::STRING,
+            'expectedSeqid' => 555,
+            'expectedException' => TProtocolException::class,
+            'expectedExceptionMessage' => 'No version identifier, old protocol client?',
+            'expectedExceptionCode' => TProtocolException::BAD_VERSION,
+        ];
+    }
+
+    public function testReadMessageEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readMessageEnd());
+    }
+
+    public function testReadStructBegin()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readStructBegin($name));
+        $this->assertEquals('', $name);
+    }
+
+    public function testReadStructEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readStructEnd());
+    }
+
+    /**
+     * @dataProvider readFieldBeginDataProvider
+     */
+    public function testReadFieldBegin(
+        $storedFieldType,
+        $readCallsParams,
+        $readCallsResults,
+        $expectedResult,
+        $expectedName,
+        $expectedFieldType,
+        $expectedFieldId
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(count($readCallsParams)))
+            ->method('readAll')
+            ->withConsecutive(...$readCallsParams)
+            ->willReturnOnConsecutiveCalls(...$readCallsResults);
+
+        $this->assertEquals($expectedResult, $protocol->readFieldBegin($name, $fieldType, $fieldId));
+        $this->assertEquals($expectedName, $name);
+        $this->assertEquals($expectedFieldType, $fieldType);
+        $this->assertEquals($expectedFieldId, $fieldId);
+    }
+
+    public function readFieldBeginDataProvider()
+    {
+        yield 'default' => [
+            'storedFieldType' => TType::STRING,
+            'readCallsParams' => [
+                [1], #readByte
+                [2], #readI16
+            ],
+            'readCallsResults' => [
+                pack('c', TType::STRING),
+                pack('n', 555),
+            ],
+            'expectedResult' => 3,
+            'exprectedName' => '',
+            'expectedFieldType' => TType::STRING,
+            'expectedFieldId' => 555,
+        ];
+
+        yield 'stop field' => [
+            'storedFieldType' => TType::STOP,
+            'readCallsParams' => [
+                [1], #readByte
+            ],
+            'readCallsResults' => [
+                pack('c', TType::STOP),
+            ],
+            'expectedResult' => 1,
+            'exprectedName' => '',
+            'expectedFieldType' => 0,
+            'expectedFieldId' => 0,
+        ];
+    }
+
+    public function testReadFieldEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readFieldEnd());
+    }
+
+    public function testReadMapBegin()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(3))
+            ->method('readAll')
+            ->withConsecutive(
+                ...[
+                       [1], #readByte
+                       [1], #readByte
+                       [4], #readI32
+                   ]
+            )->willReturnOnConsecutiveCalls(
+                pack('c', TType::I32),
+                pack('c', TType::STRING),
+                pack('N', 555)
+            );
+
+        $this->assertEquals(6, $protocol->readMapBegin($keyType, $valType, $size));
+        $this->assertEquals(TType::I32, $keyType);
+        $this->assertEquals(TType::STRING, $valType);
+        $this->assertEquals(555, $size);
+    }
+
+    public function testReadMapEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readMapEnd());
+    }
+
+    public function testReadListBegin()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(2))
+            ->method('readAll')
+            ->withConsecutive(
+                ...[
+                       [1], #readByte
+                       [4], #readI32
+                   ]
+            )->willReturnOnConsecutiveCalls(
+                pack('c', TType::I32),
+                pack('N', 555)
+            );
+
+        $this->assertEquals(5, $protocol->readListBegin($elemType, $size));
+        $this->assertEquals(TType::I32, $elemType);
+        $this->assertEquals(555, $size);
+    }
+
+    public function testReadListEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readListEnd());
+    }
+
+    public function testReadSetBegin()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(2))
+            ->method('readAll')
+            ->withConsecutive(
+                ...[
+                       [1], #readByte
+                       [4], #readI32
+                   ]
+            )->willReturnOnConsecutiveCalls(
+                pack('c', TType::I32),
+                pack('N', 555)
+            );
+
+        $this->assertEquals(5, $protocol->readSetBegin($elemType, $size));
+        $this->assertEquals(TType::I32, $elemType);
+        $this->assertEquals(555, $size);
+    }
+
+    public function testReadSetEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $this->assertEquals(0, $protocol->readSetEnd());
+    }
+
+    public function testReadBool()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('readAll')
+            ->with(1) #readByte
+            ->willReturn(pack('c', 1));
+
+        $this->assertEquals(1, $protocol->readBool($value));
+        $this->assertTrue($value);
+    }
+
+    public function testReadByte()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('readAll')
+            ->with(1) #readByte
+            ->willReturn(pack('c', 1));
+
+        $this->assertEquals(1, $protocol->readByte($value));
+        $this->assertEquals(1, $value);
+    }
+
+    /**
+     * @dataProvider readI16DataProvider
+     */
+    public function testReadI16(
+        $storedValue,
+        $expectedValue
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('readAll')
+            ->with(2) #readI16
+            ->willReturn(pack('n', $storedValue));
+
+        $this->assertEquals(2, $protocol->readI16($value));
+        $this->assertEquals($expectedValue, $value);
+    }
+
+    public function readI16DataProvider()
+    {
+        yield 'positive' => [1, 1];
+        yield 'negative' => [-1, -1];
+    }
+
+    /**
+     * @dataProvider readI16DataProvider
+     */
+    public function testReadI32(
+        $storedValue,
+        $expectedValue
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('readAll')
+            ->with(4) #readI32
+            ->willReturn(pack('N', $storedValue));
+
+        $this->assertEquals(4, $protocol->readI32($value));
+        $this->assertEquals($expectedValue, $value);
+    }
+
+    public function readI32DataProvider()
+    {
+        yield 'positive' => [1, 1];
+        yield 'negative' => [-1, -1];
+    }
+
+    /**
+     * @dataProvider readI64For32BitArchitectureDataProvider
+     */
+    public function testReadI64For32BitArchitecture(
+        $storedValue,
+        $expectedValue
+    ) {
+        if (PHP_INT_SIZE !== 4) {
+            $this->markTestSkipped('Test is only for 32 bit architecture');
+        }
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $neg = $storedValue < 0;
+
+        if ($neg) {
+            $storedValue *= -1;
+        }
+
+        $hi = (int)($storedValue / 4294967296);
+        $lo = (int)$storedValue;
+
+        if ($neg) {
+            $hi = ~$hi;
+            $lo = ~$lo;
+            if (($lo & (int)0xffffffff) == (int)0xffffffff) {
+                $lo = 0;
+                $hi++;
+            } else {
+                $lo++;
+            }
+        }
+
+        $transport
+            ->expects($this->once())
+            ->method('write')
+            ->with(pack('N2', $hi, $lo), 8) #writeI64
+            ->willReturn(4);
+
+        $this->assertEquals(8, $protocol->readI64($value));
+        $this->assertEquals($expectedValue, $value);
+    }
+
+    public function readI64For32BitArchitectureDataProvider()
+    {
+        $storedValueRepresent = function ($value) {
+            $neg = $value < 0;
+
+            if ($neg) {
+                $value *= -1;
+            }
+
+            $hi = (int)($value / 4294967296);
+            $lo = (int)$value;
+
+            if ($neg) {
+                $hi = ~$hi;
+                $lo = ~$lo;
+                if (($lo & (int)0xffffffff) == (int)0xffffffff) {
+                    $lo = 0;
+                    $hi++;
+                } else {
+                    $lo++;
+                }
+            }
+
+            return pack('N2', $hi, $lo);
+        };
+
+        yield 'positive' => [
+            'storedValue' => $storedValueRepresent(1),
+            'expectedValue' => 1,
+        ];
+
+        yield 'max' => [
+            'storedValue' => $storedValueRepresent(PHP_INT_MAX),
+            'expectedValue' => PHP_INT_MAX,
+        ];
+
+        yield 'min' => [
+            'storedValue' => $storedValueRepresent(PHP_INT_MIN),
+            'expectedValue' => PHP_INT_MIN,
+        ];
+
+        yield 'negative' => [
+            'storedValue' => $storedValueRepresent(-1),
+            'expectedValue' => -1,
+        ];
+    }
+
+    /**
+     * @dataProvider readI64For64BitArchitectureDataProvider
+     */
+    public function testReadI64For64BitArchitecture(
+        $storedValue,
+        $expectedValue
+    ) {
+        if (PHP_INT_SIZE == 4) {
+            $this->markTestSkipped('Test is only for 64 bit architecture');
+        }
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('readAll')
+            ->with(8) #readI64
+            ->willReturn($storedValue);
+
+        $this->assertEquals(8, $protocol->readI64($value));
+        $this->assertEquals($expectedValue, $value);
+    }
+
+    public function readI64For64BitArchitectureDataProvider()
+    {
+        $storedValueRepresent = function ($value) {
+            $hi = $value >> 32;
+            $lo = $value & 0xFFFFFFFF;
+
+            return pack('N2', $hi, $lo);
+        };
+
+        yield 'positive' => [
+            'storedValue' => $storedValueRepresent(1),
+            'expectedValue' => 1,
+        ];
+
+        yield 'max' => [
+            'storedValue' => $storedValueRepresent(PHP_INT_MAX),
+            'expectedValue' => PHP_INT_MAX,
+        ];
+
+        yield 'min' => [
+            'storedValue' => $storedValueRepresent(PHP_INT_MIN),
+            'expectedValue' => PHP_INT_MIN,
+        ];
+
+        yield 'negative' => [
+            'storedValue' => $storedValueRepresent(-1),
+            'expectedValue' => -1,
+        ];
+    }
+
+    public function testReadDouble()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->once())
+            ->method('readAll')
+            ->with(8) #readDouble
+            ->willReturn(strrev(pack('d', 789)));
+
+        $this->assertEquals(8, $protocol->readDouble($value));
+        $this->assertEquals(789, $value);
+    }
+
+    /**
+     * @dataProvider readStringDataProvider
+     */
+    public function testReadString(
+        $readCallsParams,
+        $readCallsResults,
+        $expectedLength,
+        $expectedValue
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TBinaryProtocol($transport, false, false);
+
+        $transport
+            ->expects($this->exactly(count($readCallsParams)))
+            ->method('readAll')
+            ->withConsecutive(...$readCallsParams)
+            ->willReturnOnConsecutiveCalls(...$readCallsResults);
+
+        $this->assertEquals($expectedLength, $protocol->readString($value));
+        $this->assertEquals($expectedValue, $value);
+    }
+
+    public function readStringDataProvider()
+    {
+        $storedValue = '';
+        yield 'empty' => [
+            'readCallsParams' => [
+                [4]
+            ],
+            'readCallsResults' => [
+                pack('N', strlen($storedValue))
+            ],
+            'expectedLength' => 4,
+            'expectedValue' => '',
+        ];
+
+        $storedValue = 'string';
+        yield 'non-empty' => [
+            'readCallsParams' => [
+                [4],
+                [strlen($storedValue)]
+            ],
+            'readCallsResults' => [
+                pack('N', strlen($storedValue)),
+                $storedValue
+            ],
+            'expectedLength' => 10,
+            'expectedValue' => 'string',
+        ];
+    }
+}
diff --git a/lib/php/test/Unit/Lib/Protocol/TCompactProtocolTest.php b/lib/php/test/Unit/Lib/Protocol/TCompactProtocolTest.php
new file mode 100644
index 0000000..95f972c
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Protocol/TCompactProtocolTest.php
@@ -0,0 +1,843 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Exception\TProtocolException;
+use Thrift\Protocol\TCompactProtocol;
+use Thrift\Transport\TTransport;
+use Thrift\Type\TType;
+
+class TCompactProtocolTest extends TestCase
+{
+    private const COMPACT_STOP = 0x00;
+    private const COMPACT_TRUE = 0x01;
+    private const COMPACT_FALSE = 0x02;
+    private const COMPACT_BYTE = 0x03;
+    private const COMPACT_I16 = 0x04;
+    private const COMPACT_I32 = 0x05;
+    private const COMPACT_I64 = 0x06;
+    private const COMPACT_DOUBLE = 0x07;
+    private const COMPACT_BINARY = 0x08;
+    private const COMPACT_LIST = 0x09;
+    private const COMPACT_SET = 0x0A;
+    private const COMPACT_MAP = 0x0B;
+    private const COMPACT_STRUCT = 0x0C;
+
+    private const STATE_CLEAR = 0;
+    private const STATE_FIELD_WRITE = 1;
+    private const STATE_VALUE_WRITE = 2;
+    private const STATE_CONTAINER_WRITE = 3;
+    private const STATE_BOOL_WRITE = 4;
+    private const STATE_FIELD_READ = 5;
+    private const STATE_CONTAINER_READ = 6;
+    private const STATE_VALUE_READ = 7;
+    private const STATE_BOOL_READ = 8;
+
+    private const VERSION_MASK = 0x1f;
+    private const VERSION = 1;
+    private const PROTOCOL_ID = 0x82;
+    private const TYPE_MASK = 0xe0;
+    private const TYPE_BITS = 0x07;
+    private const TYPE_SHIFT_AMOUNT = 5;
+
+    /**
+     * @dataProvider toZigZagDataProvider
+     */
+    public function testToZigZag(
+        $n,
+        $bits,
+        $expected
+    ) {
+        $protocol = new TCompactProtocol($this->createMock(TTransport::class));
+        $this->assertSame($expected, $protocol->toZigZag($n, $bits));
+    }
+
+    public function toZigZagDataProvider()
+    {
+        yield ['n' => 0, 'bits' => 16, 'expected' => 0];
+        yield ['n' => -1, 'bits' => 16, 'expected' => 1];
+        yield ['n' => 1, 'bits' => 16, 'expected' => 2];
+        yield ['n' => -2, 'bits' => 16, 'expected' => 3];
+        yield ['n' => 2, 'bits' => 16, 'expected' => 4];
+        yield ['n' => -1, 'bits' => 32, 'expected' => 1];
+        yield ['n' => 1, 'bits' => 32, 'expected' => 2];
+        yield ['n' => -1, 'bits' => 64, 'expected' => 1];
+        yield ['n' => 1, 'bits' => 64, 'expected' => 2];
+        yield ['n' => -0x7fffffff, 'bits' => 64, 'expected' => 4294967293];
+        yield ['n' => 0x7fffffff, 'bits' => 64, 'expected' => 4294967294];
+    }
+
+    /**
+     * @dataProvider fromZigZagDataProvider
+     */
+    public function testFromZigZag(
+        $n,
+        $expected
+    ) {
+        $protocol = new TCompactProtocol($this->createMock(TTransport::class));
+        $this->assertSame($expected, $protocol->fromZigZag($n));
+    }
+
+    public function fromZigZagDataProvider()
+    {
+        yield ['n' => 0, 'expected' => 0];
+        yield ['n' => 1, 'expected' => -1];
+        yield ['n' => 2, 'expected' => 1];
+        yield ['n' => 3, 'expected' => -2];
+        yield ['n' => 4, 'expected' => 2];
+        yield ['n' => 4294967293, 'expected' => -0x7fffffff];
+        yield ['n' => 4294967294, 'expected' => 0x7fffffff];
+    }
+
+    /**
+     * @dataProvider getVarintDataProvider
+     */
+    public function testGetVarint(
+        $data,
+        $expected
+    ) {
+        $protocol = new TCompactProtocol($this->createMock(TTransport::class));
+        $this->assertSame($expected, $protocol->getVarint($data));
+    }
+
+    public function getVarintDataProvider()
+    {
+        yield ['data' => 0, 'expected' => "\x00"];
+        yield ['data' => 1, 'expected' => "\x01"];
+        yield ['data' => 97, 'expected' => "a"];
+        yield ['data' => 100, 'expected' => "d"];
+        yield ['data' => 1000, 'expected' => "\xe8\x07"];
+    }
+
+    public function testWriteVarint()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with("\xe8\x07", 2);
+
+        $protocol->writeVarint(1000);
+    }
+
+    public function testReadVarint()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->exactly(2))
+                  ->method('readAll')
+                  ->with(1)
+                  ->willReturnOnConsecutiveCalls(
+                      ...[
+                             "\xe8",
+                             "\x07",
+                         ]
+                  );
+
+        $this->assertSame(2, $protocol->readVarint($result));
+        $this->assertSame(1000, $result);
+    }
+
+    public function testWriteMessageBegin()
+    {
+        $name = 'testName';
+        $type = TType::STRING;
+        $seqid = 1;
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport
+            ->expects($this->exactly(5))
+            ->method('write')
+            ->withConsecutive(
+                ...[
+                       [pack('C', self::PROTOCOL_ID), 1], #protocal id
+                       [pack('C', self::VERSION | ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)), 1], #version
+                       ["\x01", 1], #seqid
+                       ["\x08", 1], #field name length
+                       ["testName", 8], #field name
+                   ]
+            )->willReturnOnConsecutiveCalls(
+                1,
+                1,
+                1,
+                1,
+                8
+            );
+
+        $result = $protocol->writeMessageBegin($name, $type, $seqid);
+        $this->assertSame(12, $result);
+
+        $ref = new \ReflectionClass($protocol);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $this->assertSame(self::STATE_VALUE_WRITE, $state->getValue($protocol));
+    }
+
+    public function testWriteMessageEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $this->assertSame(0, $protocol->writeMessageEnd());
+        $ref = new \ReflectionClass($protocol);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $this->assertSame(self::STATE_CLEAR, $state->getValue($protocol));
+    }
+
+    public function testWriteStruct()
+    {
+        $name = 'testName';
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+        $ref = new \ReflectionClass($protocol);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $lastFid = $ref->getProperty('lastFid');
+        $lastFid->setAccessible(true);
+        $structs = $ref->getProperty('structs');
+        $structs->setAccessible(true);
+
+        $this->assertSame(0, $protocol->writeStructBegin($name));
+        $this->assertSame([[self::STATE_CLEAR, 0]], $structs->getValue($protocol));
+        $this->assertSame(self::STATE_FIELD_WRITE, $state->getValue($protocol));
+        $this->assertSame(0, $lastFid->getValue($protocol));
+
+        $this->assertSame(0, $protocol->writeStructBegin($name));
+        $this->assertSame(self::STATE_FIELD_WRITE, $state->getValue($protocol));
+        $this->assertSame(0, $lastFid->getValue($protocol));
+        $this->assertSame([[self::STATE_CLEAR, 0], [self::STATE_FIELD_WRITE, 0]], $structs->getValue($protocol));
+
+        $this->assertSame(0, $protocol->writeStructEnd());
+        $this->assertSame(self::STATE_FIELD_WRITE, $state->getValue($protocol));
+        $this->assertSame(0, $lastFid->getValue($protocol));
+        $this->assertSame([[self::STATE_CLEAR, 0]], $structs->getValue($protocol));
+
+        $this->assertSame(0, $protocol->writeStructEnd());
+        $this->assertSame(self::STATE_CLEAR, $state->getValue($protocol));
+        $this->assertSame(0, $lastFid->getValue($protocol));
+        $this->assertSame([], $structs->getValue($protocol));
+    }
+
+    public function testWriteFieldStop()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with("\x00", 1);
+
+        $this->assertSame(1, $protocol->writeFieldStop());
+    }
+
+    /**
+     * @dataProvider writeFieldHeaderDataProvider
+     */
+    public function testWriteFieldHeader(
+        $type,
+        $fid,
+        $writeCallParams,
+        $writeCallResult,
+        $expectedResult
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport
+            ->expects($this->exactly(count($writeCallParams)))
+            ->method('write')
+            ->withConsecutive(...$writeCallParams)
+            ->willReturnOnConsecutiveCalls(...$writeCallResult);
+
+        $this->assertSame($expectedResult, $protocol->writeFieldHeader($type, $fid));
+    }
+
+    public function writeFieldHeaderDataProvider()
+    {
+        yield 'bool' => [
+            'type' => TType::BOOL,
+            'fid' => 1,
+            'writeCallParams' => [
+                ["\x12", 1], #writeUByte(pack('C', ($delta << 4) | $type)),
+            ],
+            'writeCallResult' => [
+                1,
+            ],
+            'expectedResult' => 1,
+        ];
+        yield 'list' => [
+            'type' => TType::LST,
+            'fid' => 16,
+            'writeCallParams' => [
+                ["\x0f", 1], #writeUByte(pack('C', ($delta << 4) | $type)),
+                [" ", 1], #writeI16($fid),
+            ],
+            'writeCallResult' => [
+                1,
+            ],
+            'expectedResult' => 2,
+        ];
+    }
+
+    /**
+     * @dataProvider writeFieldBeginDataProvider
+     */
+    public function testWriteFieldBegin(
+        $fieldName,
+        $fieldType,
+        $fieldId,
+        $writeCallParams,
+        $writeCallResult,
+        $expectedState,
+        $expectedBoolFid,
+        $expectedLastFid,
+        $expectedResult
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport
+            ->expects($this->exactly(count($writeCallParams)))
+            ->method('write')
+            ->withConsecutive(...$writeCallParams)
+            ->willReturnOnConsecutiveCalls(...$writeCallResult);
+
+        $this->assertSame($expectedResult, $protocol->writeFieldBegin($fieldName, $fieldType, $fieldId));
+
+        $ref = new \ReflectionClass($protocol);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $boolFid = $ref->getProperty('boolFid');
+        $boolFid->setAccessible(true);
+        $lastFid = $ref->getProperty('lastFid');
+        $lastFid->setAccessible(true);
+        $this->assertSame($expectedState, $state->getValue($protocol));
+        $this->assertSame($expectedBoolFid, $boolFid->getValue($protocol));
+        $this->assertSame($expectedLastFid, $lastFid->getValue($protocol));
+    }
+
+    public function writeFieldBeginDataProvider()
+    {
+        yield 'bool' => [
+            'fieldName' => 'testName',
+            'fieldType' => TType::BOOL,
+            'fieldId' => 1,
+            'writeCallParams' => [],
+            'writeCallResult' => [],
+            'expectedState' => self::STATE_BOOL_WRITE,
+            'expectedBoolFid' => 1,
+            'expectedLastFid' => 0,
+            'expectedResult' => 0,
+        ];
+        yield 'list' => [
+            'fieldName' => 'testName',
+            'fieldType' => TType::LST,
+            'fieldId' => 1,
+            'writeCallParams' => [
+                ["\x19", 1], #writeUByte(pack('C', ($delta << 4) | $type)),
+            ],
+            'writeCallResult' => [
+                1,
+            ],
+            'expectedState' => self::STATE_VALUE_WRITE,
+            'expectedBoolFid' => null,
+            'expectedLastFid' => 1,
+            'expectedResult' => 1,
+        ];
+    }
+
+    public function testWriteFieldEnd()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $this->assertSame(0, $protocol->writeFieldEnd());
+
+        $ref = new \ReflectionClass($protocol);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $this->assertSame(self::STATE_FIELD_WRITE, $state->getValue($protocol));
+    }
+
+    /**
+     * @dataProvider writeCollectionDataProvider
+     */
+    public function testWriteCollection(
+        $etype,
+        $size,
+        $writeCallParams,
+        $writeCallResult,
+        $expectedState,
+        $expectedContainers,
+        $expectedResult
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport
+            ->expects($this->exactly(count($writeCallParams)))
+            ->method('write')
+            ->withConsecutive(...$writeCallParams)
+            ->willReturnOnConsecutiveCalls(...$writeCallResult);
+
+        $this->assertSame($expectedResult, $protocol->writeCollectionBegin($etype, $size));
+
+        $ref = new \ReflectionClass($protocol);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $containers = $ref->getProperty('containers');
+        $containers->setAccessible(true);
+        $this->assertSame($expectedState, $state->getValue($protocol));
+        $this->assertSame($expectedContainers, $containers->getValue($protocol));
+
+        $this->assertSame(0, $protocol->writeCollectionEnd());
+        $this->assertSame(TCompactProtocol::STATE_CLEAR, $state->getValue($protocol));
+    }
+
+    public function writeCollectionDataProvider()
+    {
+        yield 'size < 14' => [
+            'etype' => TType::STRING,
+            'size' => 1,
+            'writeCallParams' => [
+                ["\x18", 1], #writeUByte(pack('C', ($size << 4 | self::$ctypes[$etype])),
+            ],
+            'writeCallResult' => [
+                1,
+            ],
+            'expectedState' => self::STATE_CONTAINER_WRITE,
+            'expectedContainers' => [
+                0 => 0,
+            ],
+            'expectedResult' => 1,
+        ];
+        yield 'size > 14' => [
+            'etype' => TType::STRING,
+            'size' => 16,
+            'writeCallParams' => [
+                ["\xf8", 1], #writeUByte(pack('C', 0xf0 | self::$ctypes[$etype])),
+                ["\x10", 1], #writeVarint(16),
+            ],
+            'writeCallResult' => [
+                1,
+                1,
+            ],
+            'expectedState' => self::STATE_CONTAINER_WRITE,
+            'expectedContainers' => [
+                0 => 0,
+            ],
+            'expectedResult' => 2,
+        ];
+    }
+
+    /**
+     * @dataProvider writeMapDataProvider
+     */
+    public function testWriteMap(
+        $keyType,
+        $valType,
+        $size,
+        $writeCallParams,
+        $writeCallResult,
+        $expectedContainers,
+        $expectedResult
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport
+            ->expects($this->exactly(count($writeCallParams)))
+            ->method('write')
+            ->withConsecutive(...$writeCallParams)
+            ->willReturnOnConsecutiveCalls(...$writeCallResult);
+
+        $this->assertSame($expectedResult, $protocol->writeMapBegin($keyType, $valType, $size));
+
+        $ref = new \ReflectionClass($protocol);
+        $containers = $ref->getProperty('containers');
+        $containers->setAccessible(true);
+        $state = $ref->getProperty('state');
+        $state->setAccessible(true);
+        $this->assertSame($expectedContainers, $containers->getValue($protocol));
+        $this->assertSame(TCompactProtocol::STATE_CLEAR, $state->getValue($protocol));
+
+        $this->assertSame(0, $protocol->writeMapEnd());
+        $this->assertSame(TCompactProtocol::STATE_CLEAR, $state->getValue($protocol));
+        $this->assertSame([], $containers->getValue($protocol));
+    }
+
+    public function writeMapDataProvider()
+    {
+        yield 'size zero' => [
+            'keyType' => TType::STRING,
+            'valType' => TType::STRING,
+            'size' => 0,
+            'writeCallParams' => [
+                ["\x00", 1], #writeByte(0),
+            ],
+            'writeCallResult' => [
+                1,
+            ],
+            'expectedContainers' => [
+                0 => 0,
+            ],
+            'expectedResult' => 1,
+        ];
+        yield 'size non zero' => [
+            'keyType' => TType::STRING,
+            'valType' => TType::STRING,
+            'size' => 16,
+            'writeCallParams' => [
+                ["\x10", 1], #writeVarint(16),
+                ["\x88", 1], #writeUByte(pack('C', self::$ctypes[$key_type] << 4 | self::$ctypes[$val_type])),
+            ],
+            'writeCallResult' => [
+                1,
+                1,
+            ],
+            'expectedContainers' => [
+                0 => 0,
+            ],
+            'expectedResult' => 2,
+        ];
+    }
+
+    public function testWriteListBegin()
+    {
+        $protocol = $this->createPartialMock(TCompactProtocol::class, ['writeCollectionBegin']);
+
+        $protocol->expects($this->once())
+                 ->method('writeCollectionBegin')
+                 ->with(TType::STRING, 1)
+                 ->willReturn(1);
+
+        $this->assertSame(1, $protocol->writeListBegin(TType::STRING, 1));
+    }
+
+    public function testWriteListEnd()
+    {
+        $protocol = $this->createPartialMock(TCompactProtocol::class, ['writeCollectionEnd']);
+
+        $protocol->expects($this->once())
+                 ->method('writeCollectionEnd')
+                 ->willReturn(1);
+
+        $this->assertSame(1, $protocol->writeListEnd());
+    }
+
+    public function testWriteSettBegin()
+    {
+        $protocol = $this->createPartialMock(TCompactProtocol::class, ['writeCollectionBegin']);
+
+        $protocol->expects($this->once())
+                 ->method('writeCollectionBegin')
+                 ->with(TType::STRING, 1)
+                 ->willReturn(1);
+
+        $this->assertSame(1, $protocol->writeSetBegin(TType::STRING, 1));
+    }
+
+    public function testWriteSetEnd()
+    {
+        $protocol = $this->createPartialMock(TCompactProtocol::class, ['writeCollectionEnd']);
+
+        $protocol->expects($this->once())
+                 ->method('writeCollectionEnd')
+                 ->willReturn(1);
+
+        $this->assertSame(1, $protocol->writeSetEnd());
+    }
+
+    /**
+     * @dataProvider writeBinaryDataProvider
+     */
+    public function testWriteBool(
+        $value,
+        $startState,
+        $writeCallParams,
+        $writeCallResult,
+        $expectedResult,
+        $expectedException,
+        $expectedExceptionMessage
+    ) {
+        if ($expectedException) {
+            $this->expectException($expectedException);
+            $this->expectExceptionMessage($expectedExceptionMessage);
+        }
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+        if (!is_null($startState)) {
+            $ref = new \ReflectionClass($protocol);
+            $state = $ref->getProperty('state');
+            $state->setAccessible(true);
+            $state->setValue($protocol, $startState);
+        }
+
+        $transport
+            ->expects($this->exactly(count($writeCallParams)))
+            ->method('write')
+            ->withConsecutive(...$writeCallParams)
+            ->willReturnOnConsecutiveCalls(...$writeCallResult);
+
+        $this->assertSame($expectedResult, $protocol->writeBool($value));
+    }
+
+    public function writeBinaryDataProvider()
+    {
+        yield 'invalid state' => [
+            'value' => true,
+            'startState' => null,
+            'writeCallParams' => [],
+            'writeCallResult' => [],
+            'expectedResult' => 0,
+            'expectedException' => TProtocolException::class,
+            'expectedExceptionMessage' => 'Invalid state in compact protocol',
+        ];
+
+        yield 'true' => [
+            'value' => true,
+            'startState' => TCompactProtocol::STATE_BOOL_WRITE,
+            'writeCallParams' => [
+                ["\x01", 1], #writeByte
+                ["\x00", 1], #writeI16
+            ],
+            'writeCallResult' => [
+                1,
+                1,
+            ],
+            'expectedResult' => 2,
+            'expectedException' => null,
+            'expectedExceptionMessage' => null,
+        ];
+
+        yield 'false' => [
+            'value' => false,
+            'startState' => TCompactProtocol::STATE_BOOL_WRITE,
+            'writeCallParams' => [
+                ["\x02", 1], #writeByte
+                ["\x00", 1], #writeI16
+            ],
+            'writeCallResult' => [
+                1,
+                1,
+            ],
+            'expectedResult' => 2,
+            'expectedException' => null,
+            'expectedExceptionMessage' => null,
+        ];
+
+        yield 'container true' => [
+            'value' => true,
+            'startState' => TCompactProtocol::STATE_CONTAINER_WRITE,
+            'writeCallParams' => [
+                ["\x01", 1], #writeByte
+            ],
+            'writeCallResult' => [
+                1,
+            ],
+            'expectedResult' => 1,
+            'expectedException' => null,
+            'expectedExceptionMessage' => null,
+        ];
+    }
+
+    /**
+     * @dataProvider writeByteDataProvider
+     */
+    public function testWriteByte(
+        $value,
+        $expectedWriteCallParam
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with($expectedWriteCallParam, 1);
+
+        $this->assertSame(1, $protocol->writeByte($value));
+    }
+
+    public function writeByteDataProvider()
+    {
+        yield 'signed' => [
+            'value' => -1,
+            'expectedWriteCallParam' => "\xff",
+        ];
+        yield 'unsigned' => [
+            'value' => 1,
+            'expectedWriteCallParam' => "\x01",
+        ];
+        yield 'lowercase' => [
+            'value' => 'a',
+            'expectedWriteCallParam' => "\x00",
+        ];
+        yield 'upercase' => [
+            'value' => 'A',
+            'expectedWriteCallParam' => "\x00",
+        ];
+    }
+
+    /**
+     * @dataProvider writeUByteDataProvider
+     */
+    public function testWriteUByte(
+        $value,
+        $expectedWriteCallParam
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with($expectedWriteCallParam, 1);
+
+        $this->assertSame(1, $protocol->writeUByte($value));
+    }
+
+    public function writeUByteDataProvider()
+    {
+        yield 'signed' => [
+            'value' => -1,
+            'expectedWriteCallParam' => "\xff",
+        ];
+        yield 'unsigned' => [
+            'value' => 1,
+            'expectedWriteCallParam' => "\x01",
+        ];
+        yield 'lowercase' => [
+            'value' => 'a',
+            'expectedWriteCallParam' => "\x00",
+        ];
+        yield 'upercase' => [
+            'value' => 'A',
+            'expectedWriteCallParam' => "\x00",
+        ];
+    }
+
+    public function testWriteI16()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with("\x00", 1);
+
+        $this->assertSame(1, $protocol->writeI16(0));
+    }
+
+    public function testWriteI32()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with("\x00", 1);
+
+        $this->assertSame(1, $protocol->writeI32(0));
+    }
+
+    public function testWriteDouble()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with(pack('d', 0), 8);
+
+        $this->assertSame(8, $protocol->writeDouble(0));
+    }
+
+    public function testWriteString()
+    {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->exactly(2))
+                  ->method('write')
+                  ->withConsecutive(
+                      ["\x04", 1],
+                      ["test", 4]
+                  );
+
+        $this->assertSame(5, $protocol->writeString('test'));
+    }
+
+    /**
+     * @dataProvider writeI64DataProvider
+     */
+    public function testWriteI64(
+        $value,
+        $expectedWriteCallParam,
+        $expectedResult
+    ) {
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TCompactProtocol($transport);
+
+        $transport->expects($this->once())
+                  ->method('write')
+                  ->with(...$expectedWriteCallParam);
+
+        $this->assertSame($expectedResult, $protocol->writeI64($value));
+    }
+
+    public function writeI64DataProvider()
+    {
+        yield 'simple' => [
+            'value' => 0,
+            'expectedWriteCallParam' => ["\x00", 1],
+            'expectedResult' => 1,
+        ];
+        yield 'negative' => [
+            'value' => -1,
+            'expectedWriteCallParam' => ["\x01", 1],
+            'expectedResult' => 1,
+        ];
+        yield 'big' => [
+            'value' => 5000000000,
+            'expectedWriteCallParam' => [hex2bin("80c8afa025"), 5],
+            'expectedResult' => 5,
+        ];
+        yield 'small' => [
+            'value' => -5000000000,
+            'expectedWriteCallParam' => [hex2bin("ffc7afa025"), 5],
+            'expectedResult' => 5,
+        ];
+        yield 'max simple' => [
+            'value' => 0xffffffff,
+            'expectedWriteCallParam' => [hex2bin("feffffff1f"), 5],
+            'expectedResult' => 5,
+        ];
+    }
+}
diff --git a/lib/php/test/Unit/Lib/Protocol/TMultiplexedProtocolTest.php b/lib/php/test/Unit/Lib/Protocol/TMultiplexedProtocolTest.php
new file mode 100644
index 0000000..970e3a9
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Protocol/TMultiplexedProtocolTest.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Protocol\TMultiplexedProtocol;
+use Thrift\Protocol\TProtocol;
+use Thrift\Type\TMessageType;
+
+class TMultiplexedProtocolTest extends TestCase
+{
+
+    /**
+     * @dataProvider writeMessageBeginDataProvider
+     */
+    public function testWriteMessageBegin(
+        $serviceName,
+        $name,
+        $type,
+        $seqid,
+        $expectedName
+    ) {
+        $protocol = $this->createMock(TProtocol::class);
+        $multiplexedProtocol = new TMultiplexedProtocol($protocol, $serviceName);
+
+        $protocol->expects($this->once())
+            ->method('writeMessageBegin')
+            ->with($expectedName, $type, $seqid);
+
+        $multiplexedProtocol->writeMessageBegin($name, $type, $seqid);
+    }
+
+    public function writeMessageBeginDataProvider()
+    {
+        yield 'messageTypeCall' => [
+            'serviceName' => 'serviceName',
+            'name' => 'testName',
+            'type' => TMessageType::CALL,
+            'seqid' => 1,
+            'expectedName' => 'serviceName:testName'
+        ];
+        yield 'messageTypeOneWay' => [
+            'serviceName' => 'serviceName',
+            'name' => 'testName',
+            'type' => TMessageType::ONEWAY,
+            'seqid' => 1,
+            'expectedName' => 'serviceName:testName'
+        ];
+        yield 'messageTypeReply' => [
+            'serviceName' => 'serviceName',
+            'name' => 'testName',
+            'type' => TMessageType::REPLY,
+            'seqid' => 1,
+            'expectedName' => 'testName'
+        ];
+        yield 'messageTypeException' => [
+            'serviceName' => 'serviceName',
+            'name' => 'testName',
+            'type' => TMessageType::EXCEPTION,
+            'seqid' => 1,
+            'expectedName' => 'testName'
+        ];
+
+    }
+}
diff --git a/lib/php/test/Unit/Lib/Protocol/TProtocolDecoratorTest.php b/lib/php/test/Unit/Lib/Protocol/TProtocolDecoratorTest.php
new file mode 100644
index 0000000..e5dbdb3
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Protocol/TProtocolDecoratorTest.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Protocol\TProtocol;
+use Thrift\Protocol\TProtocolDecorator;
+
+class TProtocolDecoratorTest extends TestCase
+{
+
+    /**
+     * @dataProvider methodDecorationDataProvider
+     */
+    public function testMethodDecoration(
+        $methodName,
+        $methodArguments
+    ) {
+        $concreteProtocol = $this->createMock(TProtocol::class);
+        $decorator = new class ($concreteProtocol) extends TProtocolDecorator {
+            public function __construct(TProtocol $protocol)
+            {
+                parent::__construct($protocol);
+            }
+        };
+
+        $concreteProtocol->expects($this->once())
+                         ->method($methodName)
+                         ->with(...$methodArguments);
+
+        $decorator->$methodName(...$methodArguments);
+    }
+
+    public function methodDecorationDataProvider()
+    {
+        yield 'writeMessageBegin' => ['writeMessageBegin', ['name', 'type', 'seqid']];
+        yield 'writeMessageEnd' => ['writeMessageEnd', []];
+        yield 'writeStructBegin' => ['writeStructBegin', ['name']];
+        yield 'writeStructEnd' => ['writeStructEnd', []];
+        yield 'writeFieldBegin' => ['writeFieldBegin', ['name', 'type', 'id']];
+        yield 'writeFieldEnd' => ['writeFieldEnd', []];
+        yield 'writeFieldStop' => ['writeFieldStop', []];
+        yield 'writeMapBegin' => ['writeMapBegin', ['keyType', 'valType', 'size']];
+        yield 'writeMapEnd' => ['writeMapEnd', []];
+        yield 'writeListBegin' => ['writeListBegin', ['elemType', 'size']];
+        yield 'writeListEnd' => ['writeListEnd', []];
+        yield 'writeSetBegin' => ['writeSetBegin', ['elemType', 'size']];
+        yield 'writeSetEnd' => ['writeSetEnd', []];
+        yield 'writeBool' => ['writeBool', ['value']];
+        yield 'writeByte' => ['writeByte', ['value']];
+        yield 'writeI16' => ['writeI16', ['value']];
+        yield 'writeI32' => ['writeI32', ['value']];
+        yield 'writeI64' => ['writeI64', ['value']];
+        yield 'writeDouble' => ['writeDouble', ['value']];
+        yield 'writeString' => ['writeString', ['value']];
+        yield 'readMessageBegin' => ['readMessageBegin', ['name', 'type', 'seqid']];
+        yield 'readMessageEnd' => ['readMessageEnd', []];
+        yield 'readStructBegin' => ['readStructBegin', ['name']];
+        yield 'readStructEnd' => ['readStructEnd', []];
+        yield 'readFieldBegin' => ['readFieldBegin', ['name', 'type', 'id']];
+        yield 'readFieldEnd' => ['readFieldEnd', []];
+        yield 'readMapBegin' => ['readMapBegin', ['keyType', 'valType', 'size']];
+        yield 'readMapEnd' => ['readMapEnd', []];
+        yield 'readListBegin' => ['readListBegin', ['elemType', 'size']];
+        yield 'readListEnd' => ['readListEnd', []];
+        yield 'readSetBegin' => ['readSetBegin', ['elemType', 'size']];
+        yield 'readSetEnd' => ['readSetEnd', []];
+        yield 'readBool' => ['readBool', ['value']];
+        yield 'readByte' => ['readByte', ['value']];
+        yield 'readI16' => ['readI16', ['value']];
+        yield 'readI32' => ['readI32', ['value']];
+        yield 'readI64' => ['readI64', ['value']];
+        yield 'readDouble' => ['readDouble', ['value']];
+        yield 'readString' => ['readString', ['value']];
+    }
+}
diff --git a/lib/php/test/Unit/Lib/Protocol/TSimpleJSONProtocolTest.php b/lib/php/test/Unit/Lib/Protocol/TSimpleJSONProtocolTest.php
new file mode 100644
index 0000000..e4d005a
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Protocol/TSimpleJSONProtocolTest.php
@@ -0,0 +1,133 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Protocol;
+
+use PHPUnit\Framework\TestCase;
+use Thrift\Exception\TException;
+use Thrift\Protocol\TSimpleJSONProtocol;
+use Thrift\Transport\TTransport;
+use Thrift\Type\TType;
+
+class TSimpleJSONProtocolTest extends TestCase
+{
+    /**
+     * Reading methods.
+     *
+     * simplejson is not meant to be read back into thrift
+     * - see http://wiki.apache.org/thrift/ThriftUsageJava
+     * - use JSON instead
+     *
+     * @dataProvider readDataProvider
+     */
+    public function testRead(
+        $methodName,
+        $methodArguments
+    ) {
+        $this->expectException(TException::class);
+        $this->expectExceptionMessage("Not implemented");
+
+        $transport = $this->createMock(TTransport::class);
+        $protocol = new TSimpleJSONProtocol($transport);
+        $protocol->$methodName(...$methodArguments);
+    }
+
+    public function readDataProvider()
+    {
+        yield 'readMessageBegin' => [
+            'methodName' => 'readMessageBegin',
+            'methodArguments' => ['name', 'type', 'seqId'],
+        ];
+        yield 'readMessageEnd' => [
+            'methodName' => 'readMessageEnd',
+            'methodArguments' => [],
+        ];
+        yield 'readStructBegin' => [
+            'methodName' => 'readStructBegin',
+            'methodArguments' => ['name'],
+        ];
+        yield 'readStructEnd' => [
+            'methodName' => 'readStructEnd',
+            'methodArguments' => [],
+        ];
+        yield 'readFieldBegin' => [
+            'methodName' => 'readFieldBegin',
+            'methodArguments' => ['name', TType::STRING, 1],
+        ];
+        yield 'readFieldEnd' => [
+            'methodName' => 'readFieldEnd',
+            'methodArguments' => [],
+        ];
+        yield 'readMapBegin' => [
+            'methodName' => 'readMapBegin',
+            'methodArguments' => [TType::STRING, TType::STRING, 1],
+        ];
+        yield 'readMapEnd' => [
+            'methodName' => 'readMapEnd',
+            'methodArguments' => [],
+        ];
+        yield 'readListBegin' => [
+            'methodName' => 'readListBegin',
+            'methodArguments' => [TType::STRING, 1],
+        ];
+        yield 'readListEnd' => [
+            'methodName' => 'readListEnd',
+            'methodArguments' => [],
+        ];
+        yield 'readSetBegin' => [
+            'methodName' => 'readSetBegin',
+            'methodArguments' => [TType::STRING, 1],
+        ];
+        yield 'readSetEnd' => [
+            'methodName' => 'readSetEnd',
+            'methodArguments' => [],
+        ];
+        yield 'readBool' => [
+            'methodName' => 'readBool',
+            'methodArguments' => [true],
+        ];
+        yield 'readByte' => [
+            'methodName' => 'readByte',
+            'methodArguments' => [0x01],
+        ];
+        yield 'readI16' => [
+            'methodName' => 'readI16',
+            'methodArguments' => [1],
+        ];
+        yield 'readI32' => [
+            'methodName' => 'readI32',
+            'methodArguments' => [1],
+        ];
+        yield 'readI64' => [
+            'methodName' => 'readI64',
+            'methodArguments' => [1],
+        ];
+        yield 'readDouble' => [
+            'methodName' => 'readDouble',
+            'methodArguments' => [0.1],
+        ];
+        yield 'readString' => [
+            'methodName' => 'readString',
+            'methodArguments' => ['string'],
+        ];
+    }
+}
diff --git a/lib/php/test/Unit/Lib/Serializer/TBinarySerializerTest.php b/lib/php/test/Unit/Lib/Serializer/TBinarySerializerTest.php
new file mode 100644
index 0000000..292f261
--- /dev/null
+++ b/lib/php/test/Unit/Lib/Serializer/TBinarySerializerTest.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+namespace Test\Thrift\Unit\Lib\Serializer;
+
+use PHPUnit\Framework\TestCase;
+
+class TBinarySerializerTest extends TestCase
+{
+    public function testSerialize()
+    {
+        $this->markTestIncomplete('Could not test static function which create instances during execution');
+    }
+
+    public function testDeserialize()
+    {
+        $this->markTestIncomplete('Could not test static function which create instances during execution');
+    }
+}
diff --git a/lib/php/test/Unit/TJSONProtocolTest.php b/lib/php/test/Unit/TJSONProtocolTest.php
deleted file mode 100644
index 9837803..0000000
--- a/lib/php/test/Unit/TJSONProtocolTest.php
+++ /dev/null
@@ -1,514 +0,0 @@
-<?php
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-namespace Test\Thrift\Unit;
-
-use PHPUnit\Framework\TestCase;
-use Test\Thrift\Fixtures\Fixtures;
-use Test\Thrift\Fixtures\TJSONProtocolFixtures;
-use Thrift\ClassLoader\ThriftClassLoader;
-use Thrift\Protocol\TJSONProtocol;
-use Thrift\Transport\TMemoryBuffer;
-
-/***
- * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r  --out ./Resources/packages/php ./Resources/ThriftTest.thrift
- */
-class TJSONProtocolTest extends TestCase
-{
-    private $transport;
-    private $protocol;
-
-    public static function setUpBeforeClass(): void
-    {
-        $loader = new ThriftClassLoader();
-        $loader->registerNamespace('ThriftTest', __DIR__ . '/../Resources/packages/php');
-        $loader->registerDefinition('ThriftTest', __DIR__ . '/../Resources/packages/php');
-        $loader->register();
-
-        Fixtures::populateTestArgs();
-        TJSONProtocolFixtures::populateTestArgsJSON();
-    }
-
-    public function setUp(): void
-    {
-        $this->transport = new TMemoryBuffer();
-        $this->protocol = new TJSONProtocol($this->transport);
-        $this->transport->open();
-    }
-
-    /**
-     * WRITE TESTS
-     */
-    public function testVoidWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testVoid_args();
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testVoid'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString1Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->thing = Fixtures::$testArgs['testString1'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testString1'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString2Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->thing = Fixtures::$testArgs['testString2'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testString2'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testDoubleWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testDouble_args();
-        $args->thing = Fixtures::$testArgs['testDouble'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testDouble'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testByteWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testByte_args();
-        $args->thing = Fixtures::$testArgs['testByte'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testByte'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testI32Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testI32_args();
-        $args->thing = Fixtures::$testArgs['testI32'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testI32'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testI64Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testI64_args();
-        $args->thing = Fixtures::$testArgs['testI64'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testI64'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testStructWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testStruct_args();
-        $args->thing = Fixtures::$testArgs['testStruct'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testStruct'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testNestWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testNest_args();
-        $args->thing = Fixtures::$testArgs['testNest'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testNest'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testMapWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testMap_args();
-        $args->thing = Fixtures::$testArgs['testMap'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testMap'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testStringMapWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testStringMap_args();
-        $args->thing = Fixtures::$testArgs['testStringMap'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testStringMap'];
-
-        /*
-         * The $actual returns unescaped string.
-         * It is required to to decode then encode it again
-         * to get the expected escaped unicode.
-         */
-        $this->assertEquals($expected, json_encode(json_decode($actual)));
-    }
-
-    public function testSetWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testSet_args();
-        $args->thing = Fixtures::$testArgs['testSet'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testSet'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testListWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testList_args();
-        $args->thing = Fixtures::$testArgs['testList'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testList'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testEnumWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testEnum_args();
-        $args->thing = Fixtures::$testArgs['testEnum'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testEnum'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testTypedefWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testTypedef_args();
-        $args->thing = Fixtures::$testArgs['testTypedef'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testTypedef'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    /**
-     * READ TESTS
-     */
-    public function testVoidRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testVoid']
-        );
-        $args = new \ThriftTest\ThriftTest_testVoid_args();
-        $result = $args->read($this->protocol);
-
-        $this->assertEquals(0, $result);
-    }
-
-    public function testString1Read()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testString1']
-        );
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testString1'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString2Read()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testString2']
-        );
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testString2'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString3Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->thing = Fixtures::$testArgs['testString3'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testString3'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString4Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->thing = Fixtures::$testArgs['testUnicodeStringWithNonBMP'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TJSONProtocolFixtures::$testArgsJSON['testUnicodeStringWithNonBMP'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testDoubleRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testDouble']
-        );
-        $args = new \ThriftTest\ThriftTest_testDouble_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testDouble'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testByteRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testByte']
-        );
-        $args = new \ThriftTest\ThriftTest_testByte_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testByte'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testI32Read()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testI32']
-        );
-        $args = new \ThriftTest\ThriftTest_testI32_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testI32'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testI64Read()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testI64']
-        );
-        $args = new \ThriftTest\ThriftTest_testI64_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testI64'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testStructRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testStruct']
-        );
-        $args = new \ThriftTest\ThriftTest_testStruct_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testStruct'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testNestRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testNest']
-        );
-        $args = new \ThriftTest\ThriftTest_testNest_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testNest'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testMapRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testMap']
-        );
-        $args = new \ThriftTest\ThriftTest_testMap_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testMap'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testStringMapRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testStringMap']
-        );
-        $args = new \ThriftTest\ThriftTest_testStringMap_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testStringMap'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testSetRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testSet']
-        );
-        $args = new \ThriftTest\ThriftTest_testSet_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testSet'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testListRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testList']
-        );
-        $args = new \ThriftTest\ThriftTest_testList_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testList'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testEnumRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testEnum']
-        );
-        $args = new \ThriftTest\ThriftTest_testEnum_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testEnum'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testTypedefRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testTypedef']
-        );
-        $args = new \ThriftTest\ThriftTest_testTypedef_args();
-        $args->read($this->protocol);
-
-        $actual = $args->thing;
-        $expected = Fixtures::$testArgs['testTypedef'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testMapMapRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testMapMap']
-        );
-        $result = new \ThriftTest\ThriftTest_testMapMap_result();
-        $result->read($this->protocol);
-
-        $actual = $result->success;
-        $expected = Fixtures::$testArgs['testMapMapExpectedResult'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testInsanityRead()
-    {
-        $this->transport->write(
-            TJSONProtocolFixtures::$testArgsJSON['testInsanity']
-        );
-        $result = new \ThriftTest\ThriftTest_testInsanity_result();
-        $result->read($this->protocol);
-
-        $actual = $result->success;
-        $expected = Fixtures::$testArgs['testInsanityExpectedResult'];
-
-        $this->assertEquals($expected, $actual);
-    }
-}
diff --git a/lib/php/test/Unit/TSimpleJSONProtocolTest.php b/lib/php/test/Unit/TSimpleJSONProtocolTest.php
deleted file mode 100644
index 8e6a6d9..0000000
--- a/lib/php/test/Unit/TSimpleJSONProtocolTest.php
+++ /dev/null
@@ -1,247 +0,0 @@
-<?php
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-namespace Test\Thrift\Unit;
-
-use PHPUnit\Framework\TestCase;
-use Test\Thrift\Fixtures\Fixtures;
-use Test\Thrift\Fixtures\TSimpleJSONProtocolFixtures;
-use Thrift\ClassLoader\ThriftClassLoader;
-use Thrift\Protocol\TSimpleJSONProtocol;
-use Thrift\Transport\TMemoryBuffer;
-
-/***
- * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php -r  --out ./Resources/packages/php ./Resources/ThriftTest.thrift
- */
-class TSimpleJSONProtocolTest extends TestCase
-{
-    private $transport;
-    private $protocol;
-
-    public static function setUpBeforeClass(): void
-    {
-        $loader = new ThriftClassLoader();
-        $loader->registerNamespace('ThriftTest', __DIR__ . '/../Resources/packages/php');
-        $loader->registerDefinition('ThriftTest', __DIR__ . '/../Resources/packages/php');
-        $loader->register();
-
-        Fixtures::populateTestArgs();
-        TSimpleJSONProtocolFixtures::populateTestArgsSimpleJSON();
-    }
-
-    public function setUp(): void
-    {
-        $this->transport = new TMemoryBuffer();
-        $this->protocol = new TSimpleJSONProtocol($this->transport);
-        $this->transport->open();
-    }
-
-    /**
-     * WRITE TESTS
-     */
-    public function testVoidWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testVoid_args();
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testVoid'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString1Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->thing = Fixtures::$testArgs['testString1'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString1'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testString2Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testString_args();
-        $args->thing = Fixtures::$testArgs['testString2'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString2'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testDoubleWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testDouble_args();
-        $args->thing = Fixtures::$testArgs['testDouble'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testDouble'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testByteWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testByte_args();
-        $args->thing = Fixtures::$testArgs['testByte'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testByte'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testI32Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testI32_args();
-        $args->thing = Fixtures::$testArgs['testI32'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI32'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testI64Write()
-    {
-        $args = new \ThriftTest\ThriftTest_testI64_args();
-        $args->thing = Fixtures::$testArgs['testI64'];
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI64'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testStructWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testStruct_args();
-        $args->thing = Fixtures::$testArgs['testStruct'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStruct'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testNestWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testNest_args();
-        $args->thing = Fixtures::$testArgs['testNest'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testNest'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testMapWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testMap_args();
-        $args->thing = Fixtures::$testArgs['testMap'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testMap'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testStringMapWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testStringMap_args();
-        $args->thing = Fixtures::$testArgs['testStringMap'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStringMap'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testSetWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testSet_args();
-        $args->thing = Fixtures::$testArgs['testSet'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testSet'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testListWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testList_args();
-        $args->thing = Fixtures::$testArgs['testList'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testList'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testEnumWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testEnum_args();
-        $args->thing = Fixtures::$testArgs['testEnum'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testEnum'];
-
-        $this->assertEquals($expected, $actual);
-    }
-
-    public function testTypedefWrite()
-    {
-        $args = new \ThriftTest\ThriftTest_testTypedef_args();
-        $args->thing = Fixtures::$testArgs['testTypedef'];
-
-        $args->write($this->protocol);
-
-        $actual = $this->transport->read(Fixtures::$bufsize);
-        $expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testTypedef'];
-
-        $this->assertEquals($expected, $actual);
-    }
-}
diff --git a/lib/php/test/Unit/ValidatorTestOop.php b/lib/php/test/Unit/ValidatorTestOop.php
deleted file mode 100644
index 9558182..0000000
--- a/lib/php/test/Unit/ValidatorTestOop.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-namespace Test\Thrift\Unit;
-
-use Thrift\ClassLoader\ThriftClassLoader;
-
-/***
- * This test suite depends on running the compiler against the ./Resources/ThriftTest.thrift file:
- * lib/php/test$ ../../../compiler/cpp/thrift --gen php:validate,oop -r --out ./Resources/packages/phpvo ./Resources/ThriftTest.thrift
- */
-class ValidatorTestOop extends BaseValidatorTest
-{
-    public function setUp(): void
-    {
-        $loader = new ThriftClassLoader();
-        $loader->registerNamespace('ThriftTest', __DIR__ . '/../Resources/packages/phpvo');
-        $loader->registerDefinition('ThriftTest', __DIR__ . '/../Resources/packages/phpvo');
-        $loader->registerNamespace('TestValidators', __DIR__ . '/../Resources/packages/phpvo');
-        $loader->registerDefinition('TestValidators', __DIR__ . '/../Resources/packages/phpvo');
-        $loader->register();
-    }
-}
diff --git a/lib/php/test/bootstrap.php b/lib/php/test/bootstrap.php
new file mode 100644
index 0000000..c6291e5
--- /dev/null
+++ b/lib/php/test/bootstrap.php
@@ -0,0 +1,16 @@
+<?php
+
+use Thrift\ClassLoader\ThriftClassLoader;
+
+require_once __DIR__ . '/../../../vendor/autoload.php';
+
+$loader = new ThriftClassLoader();
+$loader->registerNamespace('Basic', __DIR__ . '/Resources/packages/php');
+$loader->registerNamespace('Validate', __DIR__ . '/Resources/packages/phpv');
+$loader->registerNamespace('ValidateOop', __DIR__ . '/Resources/packages/phpvo');
+$loader->registerNamespace('Json', __DIR__ . '/Resources/packages/phpjs');
+
+#do not load this namespace here, it will be loaded in ClassLoaderTest
+//$loader->registerNamespace('Server', __DIR__ . '/Resources/packages/phpcm');
+
+$loader->register();