THRIFT-2950: Fix PHP scalar set serialization - #3787
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The new array_is_list()-based detection can misclassify legacy keyed-set inputs with sequential element keys (e.g. {0,1}), causing incorrect serialization in both runtime and generated code.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates the PHP serializer (both generated PHP code and the shared runtime helpers) to accept scalar Thrift set<> values provided as sequential PHP lists, while adding regression tests for TBase/TException round-trips and JSON protocol output.
Changes:
- Accept sequential PHP arrays (e.g.
[10, 20]) as scalar-set inputs during serialization. - Apply the same compatibility logic in both
TBaseandTExceptionruntime writers and the PHP code generator. - Add unit/integration coverage for sequential set inputs (TBase, TException, TJSONProtocol).
File summaries
| File | Description |
|---|---|
| lib/php/test/Unit/Lib/Exception/TExceptionTest.php | Adds a unit test asserting round-trip behavior when a set is provided as a sequential list. |
| lib/php/test/Unit/Lib/Base/TBaseTest.php | Adds a unit test asserting round-trip behavior when a struct set field is provided as a sequential list. |
| lib/php/test/Integration/Lib/Protocol/TJSONProtocolTest.php | Adds an integration test asserting JSON serialization output for a sequential-list set input. |
| lib/php/lib/Exception/TException.php | Updates set/list writing logic to optionally serialize set values for sequential arrays. |
| lib/php/lib/Base/TBase.php | Updates set/list writing logic to optionally serialize set values for sequential arrays. |
| compiler/cpp/src/thrift/generate/t_php_generator.cc | Updates generated scalar-set serialization to choose between iterating keys vs values based on list-ness. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
The new list-vs-legacy heuristic introduces an unresolved ambiguity for set<bool> (e.g., [true]) that needs an explicit behavior decision plus tests/docs to match the PR’s stated compatibility goal.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 3
- Review effort level: Lite
There was a problem hiding this comment.
🟢 Approval recommended
The runtime and generator changes are consistent with each other and are backed by targeted unit/integration regression tests covering the key compatibility and ambiguity cases.
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 0 new
- Review effort level: Lite
a0d37f0 to
22eff1f
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Legacy keyed string-set serialization still passes uncast keys in TBase and TException.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
lib/php/lib/Base/TBase.php:368
- The legacy-marker branch still passes the raw PHP array key to the typed protocol writer. A valid legacy
set<string>such as['0' => true]is stored by PHP with integer key0, sowriteString()throws understrict_types=1; the generated serializer already recasts set keys to their declared scalar type. Cast the selected legacy key according to$etypebefore dispatch, not only for BOOL.
$elem = $set && !$setUsesValues ? $key : $val;
if ($set && !$setUsesValues && $etype === TType::BOOL) {
$elem = (bool) $elem;
lib/php/lib/Exception/TException.php:368
- The legacy-marker branch still passes the raw PHP array key to the typed protocol writer. A valid legacy
set<string>such as['0' => true]is stored by PHP with integer key0, sowriteString()throws understrict_types=1; the generated serializer already recasts set keys to their declared scalar type. Cast the selected legacy key according to$etypebefore dispatch, not only for BOOL.
if ($set && !$setUsesValues && $etype === TType::BOOL) {
$elem = (bool) $elem;
}
- Files reviewed: 8/8 changed files
- Comments generated: 1
- Review effort level: Lite
| if (elem_type->is_bool()) { | ||
| indent(out) << "if (!$" << set_uses_values << ") {" << '\n'; | ||
| indent_up(); | ||
| indent(out) << "$" << iter_elem << " = (bool) $" << iter_elem << ";" << '\n'; |
22eff1f to
b807d9a
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
Resolve typedefs before checking for boolean element types in generated set serialization.
Review details
Suppressed comments (1)
compiler/cpp/src/thrift/generate/t_php_generator.cc:2707
elem_typecan be a typedef, butt_typedefdoes not overrideis_bool(). Fortypedef bool Flag; set<Flag>, the ambiguous legacy form such as[true]therefore skips the cast and the generated strict-types code passes the integer PHP key (0) towriteBool(bool), causing aTypeError. Resolve the type before checkingis_bool()so typedef-based bool sets follow the same compatibility path.
if (elem_type->is_bool()) {
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Lite
b807d9a to
b29053e
Compare
|
Addressed the bool typedef review concern with generated-code coverage and simplification. New fixtures cover set, set (typedef bool), and a chained typedef for sequential values, legacy keyed values, ambiguous [true], and legacy true. These tests also passed before this follow-up: generate_serialize_set_element() already calls emit_array_key_recast(), which resolves typedefs and emits the bool cast. The reported TypeError was therefore not reproducible on the current branch. Removed the redundant bool-only branch instead of adding a second typedef-aware cast. Inspected regenerated PHP: all three fields cast before writeBool(). Targeted unit/integration suite: 177 tests, 336 assertions, exit 0 (2 PHPUnit deprecations); PHPCS and git diff --check pass. |
There was a problem hiding this comment.
🟡 Changes recommended
Moderate issues remain in TBase and TException for legacy string/UUID keyed sets under strict typing.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 10/10 changed files
- Comments generated: 2
- Review effort level: Lite
Client: php Generated-by: OpenAI Codex GPT-5 <noreply@openai.com>
b29053e to
09140da
Compare
|
Fixed the accelerated cross-test failures as well: the native PHP extension still serialized only keys for scalar sets. It now uses the same list-versus-all-true-marker rule as the PHP implementation. Added scalar_sets.phpt comparing native wire output with explicitly written expected Binary messages; before the change it failed for integer, string, and bool lists. Verification: 179 targeted PHP tests / 342 assertions, all 4 extension PHPT tests, and accelerated PHP clients against C++ and Python servers over buffered, framed, and HTTP transports all pass (6 cross-test runs). PHPCS and git diff --check pass. Repository-wide make style remains blocked by stale local Autotools files referencing the removed Swift directory. Previous local cross-test validation covered only the non-accelerated path; this follow-up closes that gap. CI needs to run again for the full matrix. |
There was a problem hiding this comment.
🔵 Needs a closer look
Add inline-mode coverage that verifies the serializer emits actual non-consecutive set elements.
Review details
Suppressed comments (1)
compiler/cpp/src/thrift/generate/t_php_generator.cc:2685
- The updated set loop also changes the
binary_inline_serializer, but the existing inlined test only writesnewsetand then reads it with the older V1 schema, so that field is skipped and an implementation that still serialized indexes would pass. Add an inline-mode assertion or round-trip that inspects the emitted set elements, including a non-consecutive list value.
if (php_is_scalar(elem_type)) {
- Files reviewed: 12/12 changed files
- Comments generated: 0 new
- Review effort level: Lite
Summary
Testing
Generated-by: OpenAI Codex GPT-5 noreply@openai.com