Files
Volodymyr Panivko c179da4351 THRIFT-6004: Emit native types on generated PHP service-level methods (#3483)
Client: php

Update t_php_generator to emit native PHP parameter and return types on
all generated service-level code:

* Interface (*If.php): public methods now declare typed params and
  return — `foo(?string $thing): ?string`.
* Client (*Client.php): typed constructor
  `__construct(TProtocol $input, ?TProtocol $output = null)`; typed
  `$input`/`$output`/`$seqid` properties; typed RPC methods, typed
  `send_*` (synthetic t_function with g_type_void return), typed
  `recv_*` (already synthetic; now inherits the parent
  function_signature return-type machinery).
* Processor (*Processor.php): typed
  `__construct(object $handler)`; typed
  `protected ?object $handler_ = null`; typed
  `process(TProtocol $input, TProtocol $output): bool` (changed the
  early "method not found" `return;` to `return false;` to satisfy the
  declared return type); typed
  `process_NAME(int $seqid, TProtocol $input, TProtocol $output): void`.
* Rest (*Rest.php): typed `__construct(object $impl)`; typed
  `protected object $impl;`; typed method signatures
  `methodName(array $request): ?T`; emit `return` only when the
  underlying impl method returns non-void.

Implementation
--------------

* New helper `type_to_return(t_type*)` renders `: void` or `: ?T` for
  return-type clauses, sharing the existing `type_to_native()` mapping.
* `function_signature()` extended to append `type_to_return()` for the
  return type; `argument_list()` extended to emit `?type_to_native()`
  on every parameter (previously only struct/container types were
  typed).
* `send_*` emission now constructs a synthetic
  `t_function(g_type_void, ...)` so `function_signature()` produces
  the correct `: void` for the writer half of the RPC.

Drive-by cleanup
----------------

`ThriftClassLoader::findFileInApcu()` (merged in THRIFT-6001) was
flagged by PHPStan: the trailing `$file !== false ? $file : null`
arm is unreachable because the if-branch reassigns `$file` to the
findFile() result (`?string`). Rewrote the body to a clear two-step
fetch-or-recompute and narrowed the return through `is_string()` to
satisfy the analyser without relying on a phantom else-arm.

Generated fixtures regenerate via `make stubs` in CI; nothing
checked in changes.

Part of umbrella THRIFT-5960 (PHP modernization).

Generated-by: Claude Opus 4.7
2026-05-15 19:15:53 +02:00

192 lines
4.1 KiB
PHP

<?php
use Thrift\Exception\TException;
use ThriftTest\Insanity;
use ThriftTest\Numberz;
use ThriftTest\ThriftTestIf;
use ThriftTest\Xception;
use ThriftTest\Xception2;
use ThriftTest\Xtruct;
use ThriftTest\Xtruct2;
class Handler implements ThriftTestIf
{
public function testVoid(): void
{
}
public function testString(?string $thing): ?string
{
return $thing;
}
public function testBool(?bool $thing): ?bool
{
return $thing;
}
public function testByte(?int $thing): ?int
{
return $thing;
}
public function testI32(?int $thing): ?int
{
return $thing;
}
public function testI64(?int $thing): ?int
{
return $thing;
}
public function testDouble(?float $thing): ?float
{
return $thing;
}
public function testBinary(?string $thing): ?string
{
return $thing;
}
public function testUuid(?string $thing): ?string
{
return $thing;
}
public function testStruct(?Xtruct $thing): ?Xtruct
{
return $thing;
}
public function testNest(?Xtruct2 $thing): ?Xtruct2
{
return $thing;
}
public function testMap(?array $thing): ?array
{
return $thing;
}
public function testStringMap(?array $thing): ?array
{
return $thing;
}
public function testSet(?array $thing): ?array
{
return $thing;
}
public function testList(?array $thing): ?array
{
return $thing;
}
public function testEnum(?int $thing): ?int
{
return $thing;
}
public function testTypedef(?int $thing): ?int
{
return $thing;
}
public function testMapMap(?int $hello): ?array
{
return [
-4 => [
-4 => -4,
-3 => -3,
-2 => -2,
-1 => -1,
],
4 => [
4 => 4,
3 => 3,
2 => 2,
1 => 1,
],
];
}
public function testInsanity(?Insanity $argument): ?array
{
$looney = new Insanity();
return [
1 => [
Numberz::TWO => $argument,
Numberz::THREE => $argument,
],
2 => [
Numberz::SIX => $looney,
],
];
}
public function testMulti(
?int $arg0,
?int $arg1,
?int $arg2,
?array $arg3,
?int $arg4,
?int $arg5
): ?Xtruct {
$result = new Xtruct();
$result->string_thing = 'Hello2';
$result->byte_thing = $arg0;
$result->i32_thing = $arg1;
$result->i64_thing = $arg2;
return $result;
}
public function testException(?string $arg): void
{
if ($arg === 'Xception') {
$exception = new Xception();
$exception->errorCode = 1001;
$exception->message = $arg;
throw $exception;
}
if ($arg === 'TException') {
throw new TException('This is a TException');
}
}
public function testMultiException(?string $arg0, ?string $arg1): ?Xtruct
{
if ($arg0 === 'Xception') {
$exception = new Xception();
$exception->errorCode = 1001;
$exception->message = 'This is an Xception';
throw $exception;
}
if ($arg0 === 'Xception2') {
$exception = new Xception2();
$exception->errorCode = 2002;
$exception->struct_thing = new Xtruct();
$exception->struct_thing->string_thing = 'This is an Xception2';
throw $exception;
}
$result = new Xtruct();
$result->string_thing = $arg1;
return $result;
}
public function testOneway(?int $secondsToSleep): void
{
// Keep the oneway test quick so the cross-test matrix measures fire-and-forget behavior,
// not a full second of handler blocking in the single-threaded PHP test server.
usleep((int)$secondsToSleep * 300000);
}
}