Skip to content

refactor: replace switch statements with match expressions#2524

Merged
norberttech merged 1 commit into
flow-php:1.xfrom
MrHDOLEK:refactor/switch-to-match
Jul 11, 2026
Merged

refactor: replace switch statements with match expressions#2524
norberttech merged 1 commit into
flow-php:1.xfrom
MrHDOLEK:refactor/switch-to-match

Conversation

@MrHDOLEK

@MrHDOLEK MrHDOLEK commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces switch statements with match expressions.

Changes

  • Flow\ETL\Dataset\Memory\Unit::fromString() — dispatch and the default digit-or-throw branch as one match (throw-as-expression),
  • Flow\ETL\Formatter\ASCII\ASCIIValue::mb_str_pad() — padding lengths hoisted above the match; default => $result reproduces the original no-default fall-through,
  • Flow\ETL\Adapter\Http\RequestEntriesFactory — body-entry selection as a match assignment,
  • Flow\ETL\Adapter\Parquet\SchemaConverter::flowToParquet() — 14-arm match; the $nullable ? OPTIONAL : REQUIRED ternary repeated in every case is hoisted into $repetition; ListType/MapType arms unwrap optionals through a small unwrapOptional() helper (repeated accessor calls defeat static-analysis narrowing inside a single arm expression),
  • Flow\ETL\Adapter\Seal\SchemaConverter::flowToSealField() — same treatment,
  • Flow\Parquet\Writer and Flow\Parquet\Writer\ColumnChunkBuilderFactory — compression/encoding validation as match with condition ? throw : null arms,
  • Flow\Parquet\Writer\PageBuilder\DictionaryBuilder — previously a hybrid switch around nested matches, now a single nested match,
  • Flow\Parquet\Dremel\Validator\ColumnDataValidator — nested validation matches; inner switches had no default, so the arms get an explicit default => null to preserve the silent pass-through, and case null: becomes a strict null arm.

Left as switch on purpose: ThriftModel/* and CompactProtocol (Thrift protocol field-id dispatch with multi-statement bodies / by-ref temporaries), SnappyDecompressor (hot loop with multi-variable assignments per case), PageReader, FlowTelemetryBundle (multi-statement DI configuration cases) and PlainValuesPacker (per-case @var assertions that static analysis relies on). None of these can become a match without restructuring beyond a mechanical conversion.

No public API changes. Every converted switch was checked for loose-vs-strict comparison hazards (subjects are enums, ::class strings or strtoupper() results) and for missing-default fall-throughs (match throws UnhandledMatchError where switch falls through — explicit default arms preserve the original behavior).

Verification & Benchmarks

Standard pipeline on 1M rows (from_csvbatchSize(1000)withEntry(concat)filter(endsWith) → write), PHP 8.3 + opcache, fresh process per run, medians of 3:

Scenario 1.x this PR Δ
write CSV 11.81 s 11.67 s within noise
write Parquet 13.10 s 13.30 s within noise

Peak memory unchanged (16/18 MB). Output files are byte-identical before and after the change (matching md5 for the 91 MB CSV and the 24.2 MB parquet output — the parquet variant deliberately routes through the converted SchemaConverter, DictionaryBuilder and per-value ColumnDataValidator). As expected for switch→match, this is a readability/strictness refactor, not a performance change — the benchmark is regression evidence.

Resolves: no related roadmap item — standalone modernization refactor

Change Log


Added

Fixed

Changed

  • Replaced switch statements with match expressions across core ETL, parquet lib and http/parquet/seal adapters (no behavior change, outputs byte-identical)

Removed

Deprecated

Security

@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.90283% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.34%. Comparing base (53065fd) to head (30d7a67).
⚠️ Report is 1 commits behind head on 1.x.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##                1.x    #2524      +/-   ##
============================================
+ Coverage     86.27%   86.34%   +0.07%     
+ Complexity    22924    22890      -34     
============================================
  Files          1739     1739              
  Lines         70415    70380      -35     
============================================
+ Hits          60753    60773      +20     
+ Misses         9662     9607      -55     
Components Coverage Δ
etl 89.87% <81.48%> (+<0.01%) ⬆️
cli 89.40% <ø> (ø)
lib-array-dot 81.44% <ø> (ø)
lib-azure-sdk 64.44% <ø> (ø)
lib-doctrine-dbal-bulk 93.61% <ø> (ø)
lib-filesystem 86.04% <ø> (ø)
lib-types 90.18% <ø> (ø)
lib-parquet 70.23% <88.23%> (+0.12%) ⬆️
lib-parquet-viewer 82.26% <ø> (ø)
lib-snappy 89.38% <ø> (ø)
lib-dremel 0.00% <ø> (ø)
lib-postgresql 88.62% <ø> (ø)
lib-telemetry 86.58% <ø> (ø)
bridge-filesystem-async-aws 92.74% <ø> (ø)
bridge-filesystem-azure 90.45% <ø> (ø)
bridge-monolog-http 96.82% <ø> (ø)
bridge-monolog-telemetry 94.79% <ø> (ø)
bridge-openapi-specification 92.07% <ø> (ø)
symfony-http-foundation 78.57% <ø> (ø)
bridge-psr18-telemetry 100.00% <ø> (ø)
bridge-psr3-telemetry 98.95% <ø> (ø)
bridge-psr7-telemetry 100.00% <ø> (ø)
bridge-telemetry-otlp 90.41% <ø> (ø)
bridge-symfony-http-foundation-telemetry 92.85% <ø> (ø)
bridge-symfony-filesystem-bundle 90.66% <ø> (ø)
bridge-symfony-filesystem-cache 98.18% <ø> (ø)
bridge-symfony-postgresql-bundle 93.39% <ø> (ø)
bridge-symfony-postgresql-cache 94.41% <ø> (ø)
bridge-symfony-postgresql-messenger 98.80% <ø> (ø)
bridge-symfony-postgresql-session 93.65% <ø> (ø)
bridge-symfony-telemetry-bundle 90.23% <ø> (ø)
adapter-chartjs 84.05% <ø> (ø)
adapter-csv 91.66% <ø> (ø)
adapter-doctrine 90.79% <ø> (ø)
adapter-google-sheet 99.18% <ø> (ø)
adapter-http 73.23% <100.00%> (+0.89%) ⬆️
adapter-json 88.71% <ø> (ø)
adapter-logger 50.00% <ø> (ø)
adapter-parquet 83.16% <96.15%> (+5.45%) ⬆️
adapter-text 74.13% <ø> (ø)
adapter-xml 83.40% <ø> (ø)
adapter-avro 0.00% <ø> (ø)
adapter-excel 94.21% <ø> (ø)
adapter-postgresql 91.06% <ø> (ø)
adapter-seal 93.87% <98.21%> (+8.45%) ⬆️
bridge-phpunit-postgresql 75.30% <ø> (ø)
bridge-phpunit-telemetry 87.32% <ø> (ø)
bridge-phpstan-types 0.00% <ø> (ø)
bridge-postgresql-valinor 100.00% <ø> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Converts 9 hand-written switch statements across core ETL, parquet lib
and http/parquet/seal adapters to match expressions: strict comparison,
no break fall-through, single-expression dispatch (net -100 lines).

- explicit default arms preserve original no-default fall-through
  behavior (match throws UnhandledMatchError otherwise)
- SchemaConverters get a small unwrapOptional() helper because repeated
  accessor calls inside one match arm defeat static-analysis narrowing
- Thrift protocol code, SnappyDecompressor hot loop, PageReader,
  FlowTelemetryBundle and PlainValuesPacker stay as switch (bodies not
  expressible as match arms without restructuring)

Verified: 4083 tests green, mago clean; 1M-row pipeline outputs are
byte-identical (CSV and parquet md5), timings within noise.
@MrHDOLEK MrHDOLEK force-pushed the refactor/switch-to-match branch from b202778 to 30d7a67 Compare July 11, 2026 14:03
@norberttech norberttech added the hackaton-07-2026 A first Flow Hackaton with Stloyd and MrHDOLEK 🎉 label Jul 11, 2026
@norberttech norberttech added this to the 0.42.0 milestone Jul 11, 2026
@norberttech norberttech merged commit c6f5b29 into flow-php:1.x Jul 11, 2026
48 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Roadmap Jul 11, 2026
@norberttech

Copy link
Copy Markdown
Member

I merged it mostly due to better DX, the perf improvement is hard to verify here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hackaton-07-2026 A first Flow Hackaton with Stloyd and MrHDOLEK 🎉 size: L

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants