From 4bf62abd83760f75e005b40f91907593458d3583 Mon Sep 17 00:00:00 2001 From: Volodymyr Panivko Date: Fri, 29 May 2026 23:32:11 +0200 Subject: [PATCH] THRIFT-6023: Add HTTP transport support to PHP cross-tests Client: php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHP was the only major-language entry stuck on buffered/framed sockets while Python, Go, Node, C++, Java, Lua, Dart, JS, D, and Haskell already declared http in their cross-test transports. Server (test/php/TestServer.php + HttpRouter.php + HttpServer.php): - On --transport=http, TestServer pcntl_exec()s into 'php -S' with HttpRouter.php as the router. The chameleon HttpRouter dispatches on PHP_SAPI: cli launches php -S with itself as the per-request handler; cli-server invokes HttpServer. - HttpServer reads php://input via TMemoryBuffer, peeks the message type, and for ONEWAY sends an empty HTTP 200 immediately while forking the handler so strict clients (Java) measure fast oneway latency. Sync path echoes the processor's response bytes. - protocols.php centralises the protocol-name -> TProtocolFactory dispatch, shared between the socket entry point and the cli-server router. Client (test/php/TestClient.php): - Adds an http branch that uses TPsrHttpClient (THRIFT-6010) against http://127.0.0.1:$port/. Drops the duplicate makeProtocol() helper in favour of thrift_test_protocol_factory()->getProtocol(), removes the unused $host argv parsing, and normalises the file to PSR-12. composer.json: adds guzzlehttp/guzzle ^7.8 to require-dev so PSR-18 discovery resolves a real client at cross-test time. test/tests.json: adds 'http' to PHP server and client transports. test/known_failures_Linux.json: lists php-cpp_*_http-ip (cpp THttpClient does not handle Connection: close between calls — tracked as THRIFT-6060) and nodejs-php_*_http-ip (Node http server mounts /test, not /, matching the existing cpp-/d-/go-nodejs known failures). Generated-by: Claude Opus 4.7 --- composer.json | 1 + test/known_failures_Linux.json | 8 + test/php/HttpRouter.php | 77 +++++++ test/php/HttpServer.php | 117 +++++++++++ test/php/TestClient.php | 364 +++++++++++++++------------------ test/php/TestServer.php | 56 ++--- test/php/protocols.php | 49 +++++ test/tests.json | 6 +- 8 files changed, 431 insertions(+), 247 deletions(-) create mode 100644 test/php/HttpRouter.php create mode 100644 test/php/HttpServer.php create mode 100644 test/php/protocols.php diff --git a/composer.json b/composer.json index f41bb1f1f1d..8cc315d3981 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,7 @@ "php-mock/php-mock-phpunit": "^2.10", "phpstan/phpstan": "^1.12", "nyholm/psr7": "^1.8", + "guzzlehttp/guzzle": "^7.8", "ext-json": "*", "ext-xml": "*", "ext-curl": "*", diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json index c85c25bc185..e283fd97116 100644 --- a/test/known_failures_Linux.json +++ b/test/known_failures_Linux.json @@ -588,6 +588,10 @@ "nodejs-nodejs_compact_websocket-domain", "nodejs-nodejs_header_websocket-domain", "nodejs-nodejs_json_websocket-domain", + "nodejs-php_binary-accel_http-ip", + "nodejs-php_binary_http-ip", + "nodejs-php_compact_http-ip", + "nodejs-php_json_http-ip", "nodejs-py_binary-accel_http-domain", "nodejs-py_binary-accel_http-ip", "nodejs-py_binary-accel_http-ip-ssl", @@ -615,6 +619,10 @@ "perl-netstd_multi-binary_buffered-ip-ssl", "perl-netstd_multi-binary_framed-ip", "perl-netstd_multi-binary_framed-ip-ssl", + "php-cpp_accel-binary_http-ip", + "php-cpp_binary_http-ip", + "php-cpp_compact_http-ip", + "php-cpp_json_http-ip", "py-cpp_accel-binary_http-domain", "py-cpp_accel-binary_http-ip", "py-cpp_accel-binary_http-ip-ssl", diff --git a/test/php/HttpRouter.php b/test/php/HttpRouter.php new file mode 100644 index 00000000000..16d1ccd8f7f --- /dev/null +++ b/test/php/HttpRouter.php @@ -0,0 +1,77 @@ +registerDefinition('ThriftTest', __DIR__ . '/gen-php-classmap'); + $loader->register(); + + require_once __DIR__ . '/Handler.php'; + + $protocolFactory = thrift_test_protocol_factory(getenv('THRIFT_TEST_PROTOCOL') ?: 'binary'); + $processor = new ThriftTest\ThriftTestProcessor(new Handler()); + + (new HttpServer($processor, $protocolFactory))->serve(); + return; +} + +// CLI launcher: sourced from TestServer.php; $port and $protocol are in scope. +if (!function_exists('pcntl_exec')) { + fwrite(STDERR, "PHP HTTP cross-test requires ext-pcntl.\n"); + exit(1); +} + +$env = getenv(); +$env['THRIFT_TEST_PROTOCOL'] = $protocol; + +echo "Starting the Test server (HTTP via php -S)...\n"; + +// -d flags mirror the launcher invocation in test/tests.json — keep in sync. +pcntl_exec(PHP_BINARY, [ + '-dextension_dir=php_ext_dir', + '-dextension=thrift_protocol.so', + '-ddisplay_errors=stderr', + '-dlog_errors=0', + '-derror_reporting=E_ALL', + '-S', '127.0.0.1:' . $port, + __FILE__, +], $env); + +fwrite(STDERR, "pcntl_exec failed\n"); +exit(1); diff --git a/test/php/HttpServer.php b/test/php/HttpServer.php new file mode 100644 index 00000000000..0e074ba62da --- /dev/null +++ b/test/php/HttpServer.php @@ -0,0 +1,117 @@ +peekMessageType($requestBody) === TMessageType::ONEWAY + && function_exists('pcntl_fork') + && $this->dispatchOnewayAsync($requestBody) + ) { + return; + } + + $this->dispatchSync($requestBody); + } + + private function peekMessageType(string $body): ?int + { + if ($body === '') { + return null; + } + try { + $type = null; + $name = null; + $seqid = null; + $this->protocolFactory + ->getProtocol(new TMemoryBuffer($body)) + ->readMessageBegin($name, $type, $seqid); + + return $type; + } catch (\Throwable) { + return null; + } + } + + private function dispatchOnewayAsync(string $body): bool + { + header('Content-Length: 0'); + $pid = pcntl_fork(); + if ($pid > 0) { + return true; + } + if ($pid === 0) { + if (defined('STDIN')) { + fclose(STDIN); + } + if (defined('STDOUT')) { + fclose(STDOUT); + } + if (defined('STDERR')) { + fclose(STDERR); + } + $this->processor->process( + $this->protocolFactory->getProtocol(new TMemoryBuffer($body)), + $this->protocolFactory->getProtocol(new TMemoryBuffer()), + ); + exit(0); + } + + return false; + } + + private function dispatchSync(string $body): void + { + $output = new TMemoryBuffer(); + $this->processor->process( + $this->protocolFactory->getProtocol(new TMemoryBuffer($body)), + $this->protocolFactory->getProtocol($output), + ); + echo $output->getBuffer(); + } +} diff --git a/test/php/TestClient.php b/test/php/TestClient.php index c9e1ba7e5ec..20e5b1a5e4b 100755 --- a/test/php/TestClient.php +++ b/test/php/TestClient.php @@ -1,28 +1,5 @@ addPsr4('', $GEN_DIR); -} else { - $loader = new ThriftClassLoader(); - $loader->registerDefinition('ThriftTest', $GEN_DIR); - $loader->register(); -} - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -42,23 +19,35 @@ * under the License. */ +namespace test\php; + use Psr\Log\AbstractLogger; use Psr\Log\LoggerInterface; +use Thrift\ClassLoader\ThriftClassLoader; +use Thrift\Transport\TBufferedTransport; +use Thrift\Transport\TFramedTransport; +use Thrift\Transport\TPsrHttpClient; +use Thrift\Transport\TSocketPool; -/** Include the Thrift base */ -/** Include the protocols */ -use Thrift\Protocol\TBinaryProtocol; -use Thrift\Protocol\TBinaryProtocolAccelerated; -use Thrift\Protocol\TCompactProtocol; -use Thrift\Protocol\TJSONProtocol; +/** @var \Composer\Autoload\ClassLoader $loader */ +$loader = require __DIR__ . '/../../vendor/autoload.php'; -/** Include the socket layer */ -use Thrift\Transport\TSocket; -use Thrift\Transport\TSocketPool; +if (!isset($GEN_DIR)) { + $GEN_DIR = 'gen-php'; +} +if (!isset($MODE)) { + $MODE = 'normal'; +} -/** Include the socket layer */ -use Thrift\Transport\TFramedTransport; -use Thrift\Transport\TBufferedTransport; +if ($GEN_DIR == 'gen-php') { + $loader->addPsr4('', $GEN_DIR); +} else { + $loader = new ThriftClassLoader(); + $loader->registerDefinition('ThriftTest', $GEN_DIR); + $loader->register(); +} + +require_once __DIR__ . '/protocols.php'; /** * Minimal PSR-3 logger that forwards every message to PHP's error_log @@ -78,67 +67,33 @@ public function log($level, $message, array $context = []): void } } -function makeProtocol($transport, $PROTO) -{ - if ($PROTO == 'binary') { - return new TBinaryProtocol($transport); - } else if ($PROTO == 'compact') { - return new TCompactProtocol($transport); - } else if ($PROTO == 'json') { - return new TJSONProtocol($transport); - } else if ($PROTO == 'accel') { - if (!function_exists('thrift_protocol_write_binary')) { - echo "Acceleration extension is not loaded\n"; - exit(1); - } - return new TBinaryProtocolAccelerated($transport); - } - - echo "--protocol must be one of {binary|compact|json|accel}\n"; - exit(1); -} - -$host = 'localhost'; $port = 9090; -if ($argc > 1) { - $host = $argv[0]; +foreach ($argv as $arg) { + if (substr($arg, 0, 7) == '--port=') { + $port = (int) substr($arg, 7); + } elseif (substr($arg, 0, 12) == '--transport=') { + $MODE = substr($arg, 12); + } elseif (substr($arg, 0, 11) == '--protocol=') { + $PROTO = substr($arg, 11); + } } -if ($argc > 2) { - $host = $argv[1]; -} +// TPsrHttpClient buffers internally, so no framed/buffered wrapper is needed. +// Inline mode passes the raw transport to the generated client without a +// protocol wrapper, matching the legacy code path. +$transport = match ($MODE) { + 'http' => new TPsrHttpClient(sprintf('http://127.0.0.1:%d/', $port)), + default => new TSocketPool(['localhost'], $port, false, new StderrLogger()), +}; +$transport = match ($MODE) { + 'framed' => new TFramedTransport($transport), + 'http', 'inline' => $transport, + default => new TBufferedTransport($transport, 1024, 1024), +}; -foreach ($argv as $arg) { - if (substr($arg, 0, 7) == '--port=') { - $port = (int) substr($arg, 7); - } else if (substr($arg, 0, 12) == '--transport=') { - $MODE = substr($arg, 12); - } else if (substr($arg, 0, 11) == '--protocol=') { - $PROTO = substr($arg, 11); - } -} - -$hosts = array('localhost'); - -$logger = new StderrLogger(); -$socket = new TSocket($host, $port, false, $logger); -$socket = new TSocketPool($hosts, $port, false, $logger); - -if ($MODE == 'inline') { - $transport = $socket; - $testClient = new \ThriftTest\ThriftTestClient($transport); -} else if ($MODE == 'framed') { - $framedSocket = new TFramedTransport($socket); - $transport = $framedSocket; - $protocol = makeProtocol($transport, $PROTO); - $testClient = new \ThriftTest\ThriftTestClient($protocol); -} else { - $bufferedSocket = new TBufferedTransport($socket, 1024, 1024); - $transport = $bufferedSocket; - $protocol = makeProtocol($transport, $PROTO); - $testClient = new \ThriftTest\ThriftTestClient($protocol); -} +$protocol = $MODE === 'inline' ? null : thrift_test_protocol_factory($PROTO)->getProtocol($transport); +$testClient = new \ThriftTest\ThriftTestClient($protocol ?? $transport); $transport->open(); @@ -150,6 +105,7 @@ function makeProtocol($transport, $PROTO) define('ERR_EXCEPTIONS', 8); define('ERR_UNKNOWN', 64); $exitcode = 0; + /** * VOID TEST */ @@ -157,15 +113,16 @@ function makeProtocol($transport, $PROTO) $testClient->testVoid(); print_r(" = void\n"); -function roundtrip($testClient, $method, $value) { - global $exitcode; - print_r("$method($value)"); - $ret = $testClient->$method($value); - print_r(" = \"$ret\"\n"); - if ($value !== $ret) { - print_r("*** FAILED ***\n"); - $exitcode |= ERR_BASETYPES; - } +function roundtrip($testClient, $method, $value) +{ + global $exitcode; + print_r("$method($value)"); + $ret = $testClient->$method($value); + print_r(" = \"$ret\"\n"); + if ($value !== $ret) { + print_r("*** FAILED ***\n"); + $exitcode |= ERR_BASETYPES; + } } /** @@ -234,10 +191,10 @@ function roundtrip($testClient, $method, $value) { $out->i32_thing = -3; $out->i64_thing = -5; $in = $testClient->testStruct($out); -print_r(" = {\"".$in->string_thing."\", ". - $in->byte_thing.", ". - $in->i32_thing.", ". - $in->i64_thing."}\n"); +print_r(" = {\"" . $in->string_thing . "\", " . + $in->byte_thing . ", " . + $in->i32_thing . ", " . + $in->i64_thing . "}\n"); if ($in != $out) { echo "**FAILED**\n"; @@ -254,12 +211,12 @@ function roundtrip($testClient, $method, $value) { $out2->i32_thing = 5; $in2 = $testClient->testNest($out2); $in = $in2->struct_thing; -print_r(" = {".$in2->byte_thing.", {\"". - $in->string_thing."\", ". - $in->byte_thing.", ". - $in->i32_thing.", ". - $in->i64_thing."}, ". - $in2->i32_thing."}\n"); +print_r(" = {" . $in2->byte_thing . ", {\"" . + $in->string_thing . "\", " . + $in->byte_thing . ", " . + $in->i32_thing . ", " . + $in->i64_thing . "}, " . + $in2->i32_thing . "}\n"); if ($in2 != $out2) { echo "**FAILED**\n"; @@ -269,19 +226,19 @@ function roundtrip($testClient, $method, $value) { /** * MAP TEST */ -$mapout = array(); +$mapout = []; for ($i = 0; $i < 5; ++$i) { - $mapout[$i] = $i-10; + $mapout[$i] = $i - 10; } print_r("testMap({"); $first = true; foreach ($mapout as $key => $val) { - if ($first) { - $first = false; - } else { - print_r(", "); - } - print_r("$key => $val"); + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r("$key => $val"); } print_r("})"); @@ -289,12 +246,12 @@ function roundtrip($testClient, $method, $value) { print_r(" = {"); $first = true; foreach ($mapin as $key => $val) { - if ($first) { - $first = false; - } else { - print_r(", "); - } - print_r("$key => $val"); + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r("$key => $val"); } print_r("}\n"); @@ -303,31 +260,31 @@ function roundtrip($testClient, $method, $value) { $exitcode |= ERR_CONTAINERS; } -$mapout = array(); +$mapout = []; for ($i = 0; $i < 10; $i++) { $mapout["key$i"] = "val$i"; } print_r('testStringMap({'); $first = true; foreach ($mapout as $key => $val) { - if ($first) { - $first = false; - } else { - print_r(", "); - } - print_r("\"$key\" => \"$val\""); + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r("\"$key\" => \"$val\""); } print_r("})"); $mapin = $testClient->testStringMap($mapout); print_r(" = {"); $first = true; foreach ($mapin as $key => $val) { - if ($first) { - $first = false; - } else { - print_r(", "); - } - print_r("\"$key\" => \"$val\""); + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r("\"$key\" => \"$val\""); } print_r("}\n"); ksort($mapin); @@ -339,9 +296,9 @@ function roundtrip($testClient, $method, $value) { /** * SET TEST */ -$setout = array();; +$setout = []; for ($i = -2; $i < 3; ++$i) { - $setout[$i]= true; + $setout[$i] = true; } print_r("testSet({"); echo implode(',', array_keys($setout)); @@ -365,31 +322,31 @@ function roundtrip($testClient, $method, $value) { /** * LIST TEST */ -$listout = array(); +$listout = []; for ($i = -2; $i < 3; ++$i) { - $listout []= $i; + $listout[] = $i; } print_r("testList({"); $first = true; foreach ($listout as $val) { - if ($first) { - $first = false; - } else { - print_r(", "); - } - print_r($val); + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r($val); } print_r("})"); $listin = $testClient->testList($listout); print_r(" = {"); $first = true; foreach ($listin as $val) { - if ($first) { - $first = false; - } else { - print_r(", "); - } - print_r($val); + if ($first) { + $first = false; + } else { + print_r(", "); + } + print_r($val); } print_r("}\n"); if ($listin !== $listout) { @@ -458,16 +415,16 @@ function roundtrip($testClient, $method, $value) { $mm = $testClient->testMapMap(1); print_r(" = {"); foreach ($mm as $key => $val) { - print_r("$key => {"); - foreach ($val as $k2 => $v2) { - print_r("$k2 => $v2, "); - } - print_r("}, "); + print_r("$key => {"); + foreach ($val as $k2 => $v2) { + print_r("$k2 => $v2, "); + } + print_r("}, "); } print_r("}\n"); $expected_mm = [ - -4 => [-4 => -4, -3 => -3, -2 => -2, -1 => -1], - 4 => [4 => 4, 3 => 3, 2 => 2, 1 => 1], + -4 => [-4 => -4, -3 => -3, -2 => -2, -1 => -1], + 4 => [4 => 4, 3 => 3, 2 => 2, 1 => 1], ]; if ($mm != $expected_mm) { echo "**FAILED**\n"; @@ -484,36 +441,36 @@ function roundtrip($testClient, $method, $value) { $truck->byte_thing = 8; $truck->i32_thing = 8; $truck->i64_thing = 8; -$insane->xtructs []= $truck; +$insane->xtructs[] = $truck; print_r("testInsanity()"); $whoa = $testClient->testInsanity($insane); print_r(" = {"); foreach ($whoa as $key => $val) { - print_r("$key => {"); - foreach ($val as $k2 => $v2) { - print_r("$k2 => {"); - $userMap = $v2->userMap; - print_r("{"); - if (is_array($userMap)) { - foreach ($userMap as $k3 => $v3) { - print_r("$k3 => $v3, "); - } + print_r("$key => {"); + foreach ($val as $k2 => $v2) { + print_r("$k2 => {"); + $userMap = $v2->userMap; + print_r("{"); + if (is_array($userMap)) { + foreach ($userMap as $k3 => $v3) { + print_r("$k3 => $v3, "); + } + } + print_r("}, "); + + $xtructs = $v2->xtructs; + print_r("{"); + if (is_array($xtructs)) { + foreach ($xtructs as $x) { + print_r("{\"" . $x->string_thing . "\", " . + $x->byte_thing . ", " . $x->i32_thing . ", " . $x->i64_thing . "}, "); + } + } + print_r("}"); + + print_r("}, "); } print_r("}, "); - - $xtructs = $v2->xtructs; - print_r("{"); - if (is_array($xtructs)) { - foreach ($xtructs as $x) { - print_r("{\"".$x->string_thing."\", ". - $x->byte_thing.", ".$x->i32_thing.", ".$x->i64_thing."}, "); - } - } - print_r("}"); - - print_r("}, "); - } - print_r("}, "); } print_r("}\n"); @@ -522,30 +479,30 @@ function roundtrip($testClient, $method, $value) { */ print_r("testException('Xception')"); try { - $testClient->testException('Xception'); - print_r(" void\nFAILURE\n"); - $exitcode |= ERR_EXCEPTIONS; + $testClient->testException('Xception'); + print_r(" void\nFAILURE\n"); + $exitcode |= ERR_EXCEPTIONS; } catch (\ThriftTest\Xception $x) { - print_r(' caught xception '.$x->errorCode.': '.$x->message."\n"); + print_r(' caught xception ' . $x->errorCode . ': ' . $x->message . "\n"); } // Regression test for THRIFT-4263 print_r("testBinarySerializer_Deserialize('foo')"); try { - \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class); - echo "**FAILED**\n"; - $exitcode |= ERR_STRUCTS; + \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class); + echo "**FAILED**\n"; + $exitcode |= ERR_STRUCTS; } catch (\Thrift\Exception\TTransportException $happy_exception) { - // We expected this due to binary data of base64_decode('foo') is less then 4 - // bytes and it tries to find thrift version number in the transport by - // reading i32() at the beginning. Casting to string validates that - // exception is still accessible in memory and not corrupted. Without patch, - // PHP will error log that the exception doesn't have any tostring method, - // which is a lie due to corrupted memory. - for($i=99; $i > 0; $i--) { - (string)$happy_exception; - } - print_r(" SUCCESS\n"); + // We expected this due to binary data of base64_decode('foo') is less then 4 + // bytes and it tries to find thrift version number in the transport by + // reading i32() at the beginning. Casting to string validates that + // exception is still accessible in memory and not corrupted. Without patch, + // PHP will error log that the exception doesn't have any tostring method, + // which is a lie due to corrupted memory. + for ($i = 99; $i > 0; $i--) { + (string) $happy_exception; + } + print_r(" SUCCESS\n"); } /** @@ -553,14 +510,14 @@ function roundtrip($testClient, $method, $value) { */ $stop = microtime(true); -$elp = round(1000*($stop - $start), 0); +$elp = round(1000 * ($stop - $start), 0); print_r("Total time: $elp ms\n"); /** * Extraneous "I don't trust PHP to pack/unpack integer" tests */ -if ($protocol instanceof TBinaryProtocolAccelerated) { +if ($protocol instanceof \Thrift\Protocol\TBinaryProtocolAccelerated) { // Regression check: check that method name is not double-freed // Method name should not be an interned string. $method_name = "Void"; @@ -570,7 +527,6 @@ function roundtrip($testClient, $method, $value) { $args = new \ThriftTest\ThriftTest_testVoid_args(); thrift_protocol_write_binary($protocol, $method_name, \Thrift\Type\TMessageType::CALL, $args, $seqid, $protocol->isStrictWrite()); $testClient->recv_testVoid(); - } // Max I32 diff --git a/test/php/TestServer.php b/test/php/TestServer.php index 4ab773cb88c..bdcb25056c9 100644 --- a/test/php/TestServer.php +++ b/test/php/TestServer.php @@ -3,6 +3,7 @@ error_reporting(E_ALL); require_once __DIR__ . '/../../vendor/autoload.php'; +require_once __DIR__ . '/protocols.php'; $opts = getopt( 'h::', @@ -47,57 +48,30 @@ $transport = $opts['transport'] ?? 'buffered'; $protocol = $opts['protocol'] ?? 'binary'; +// HTTP transport: delegate to HttpRouter (its CLI-launcher branch execs into +// `php -S` with HttpRouter itself as the per-request handler). +if ($transport === 'http') { + require __DIR__ . '/HttpRouter.php'; + return; +} -$loader = new Thrift\ClassLoader\ThriftClassLoader(); +$loader = new \Thrift\ClassLoader\ThriftClassLoader(); $loader->registerDefinition('ThriftTest', __DIR__ . '/gen-php-classmap'); $loader->register(); -$sslOptions = \stream_context_create( - [ - 'ssl' => [ - 'verify_peer' => false, - 'verify_peer_name' => false, - ], - ] -); - require_once __DIR__ . '/Handler.php'; -switch ($transport) { - case 'framed': - $serverTransportFactory = new \Thrift\Factory\TFramedTransportFactory(); - break; - default: - $serverTransportFactory = new \Thrift\Factory\TTransportFactory(); -} +$serverTransportFactory = match ($transport) { + 'framed' => new \Thrift\Factory\TFramedTransportFactory(), + default => new \Thrift\Factory\TTransportFactory(), +}; -switch ($protocol) { - case 'binary': - $protocolFactory = new \Thrift\Factory\TBinaryProtocolFactory(false, true); - break; - case 'accel': - if (!function_exists('thrift_protocol_write_binary')) { - fwrite(STDERR, "Acceleration extension is not loaded\n"); - exit(1); - } - $protocolFactory = new \Thrift\Factory\TBinaryProtocolAcceleratedFactory(); - break; - case 'compact': - $protocolFactory = new \Thrift\Factory\TCompactProtocolFactory(); - break; - case 'json': - $protocolFactory = new \Thrift\Factory\TJSONProtocolFactory(); - break; - default: - fwrite(STDERR, "--protocol must be one of {binary|compact|json|accel}\n"); - exit(1); -} +$protocolFactory = thrift_test_protocol_factory($protocol); // `localhost` may resolve to an IPv6-only listener in newer PHP/runtime combinations, // while some cross-test clients still connect via 127.0.0.1. Bind explicitly to IPv4. $serverTransport = new \Thrift\Server\TServerSocket('127.0.0.1', $port); -$handler = new Handler(); -$processor = new ThriftTest\ThriftTestProcessor($handler); +$processor = new \ThriftTest\ThriftTestProcessor(new \Handler()); $server = new \Thrift\Server\TSimpleServer( $processor, @@ -105,7 +79,7 @@ $serverTransportFactory, $serverTransportFactory, $protocolFactory, - $protocolFactory + $protocolFactory, ); echo "Starting the Test server...\n"; diff --git a/test/php/protocols.php b/test/php/protocols.php new file mode 100644 index 00000000000..64f2287202b --- /dev/null +++ b/test/php/protocols.php @@ -0,0 +1,49 @@ +