Add std-out/simple-data-objects to benchmark comparison - #116
Conversation
Adds the compiled-closure DTO library std-out/simple-data-objects to the external comparison, requested by its author so the numbers are reproducible on both sides. - run-external.php: simple and nested creation, auto-detected like the other libraries and skipped when absent. - run-sdo.php: a dedicated head-to-head covering hydration, serialization, field transforms (their Cast and Pipe paths) and per-instance memory, since run-external only measures hydration. - generate.php: regenerates the benchmark DTOs with strictTypes enabled, which the bin/dto CLI does not expose and which transform inlining needs. The dependency requires PHP 8.4+, so it stays out of require-dev (which would break composer install on 8.2/8.3) and lives under suggest; install it with composer require --dev std-out/simple-data-objects.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #116 +/- ##
=========================================
Coverage 83.20% 83.20%
Complexity 1569 1569
=========================================
Files 46 46
Lines 3859 3859
=========================================
Hits 3211 3211
Misses 648 648 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds std-out/simple-data-objects as an opt-in benchmark target and introduces a dedicated head-to-head script to compare hydration/serialization/transforms/memory against php-collective/dto, plus regeneration of generated benchmark DTOs with strictTypes enabled for transform inlining.
Changes:
- Extend
run-external.phpto auto-detect and benchmark simple-data-objects (flat + nested hydration), including configuring its on-disk metadata cache. - Add
run-sdo.phpfor a direct comparison across scenarios (hydration, serialization, transforms, per-instance memory) and add mirror DTO shapes underbenchmark/src/SimpleDataObjects/. - Add
benchmark/generate.phpand updatebenchmark/config/dto.phpto generate benchmark DTOs withstrictTypes, plus README/composer updates for opt-in installation viasuggest.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| benchmark/src/Support/UcfirstTrimPipe.php | Adds a simple-data-objects Pipe implementation used in transform benchmarks. |
| benchmark/src/Support/UcfirstCast.php | Adds a simple-data-objects Cast implementation used in transform benchmarks. |
| benchmark/src/Support/Transform.php | Centralizes transform helpers used by generated benchmark DTO config. |
| benchmark/src/SimpleDataObjects/UserData.php | Adds flat mirror DTO for simple-data-objects hydration/serialization scenarios. |
| benchmark/src/SimpleDataObjects/TransformUserData.php | Adds Pipe-based transform mirror DTO for simple-data-objects. |
| benchmark/src/SimpleDataObjects/TransformUserCastData.php | Adds Cast-based transform mirror DTO for simple-data-objects. |
| benchmark/src/SimpleDataObjects/OrderItemData.php | Adds nested mirror DTO component for simple-data-objects. |
| benchmark/src/SimpleDataObjects/OrderData.php | Adds nested order mirror DTO (incl. collection + DateTime cast) for simple-data-objects. |
| benchmark/src/SimpleDataObjects/MiniData.php | Adds minimal mirror DTO for small-scenario comparisons. |
| benchmark/src/SimpleDataObjects/AddressData.php | Adds address mirror DTO for nested scenarios. |
| benchmark/run-sdo.php | New head-to-head benchmark script covering hydration, serialization, transforms, and memory. |
| benchmark/run-external.php | Adds simple-data-objects to external comparison + configures its cache directory. |
| benchmark/README.md | Documents opt-in install (PHP 8.4+) and new head-to-head workflow. |
| benchmark/generate.php | Adds generator wrapper to regenerate benchmark DTOs with strictTypes enabled. |
| benchmark/config/dto.php | Adds TransformUser + Mini definitions used by the head-to-head script and strictTypes generation. |
| benchmark/composer.json | Adds suggest entry for opt-in simple-data-objects dependency (PHP 8.4+). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Exit with a clear message when std-out/simple-data-objects or the generated DTOs are absent, instead of a fatal. - Verify each scenario produces identical output on both sides before timing, so the ratios always compare equal work.
Results: php-collective/dto vs std-out/simple-data-objectsRan Who wins what
Reading of it
Net: the two libraries trade blows along a clean line. simple-data-objects is the faster hydrator with a much smaller footprint; php-collective/dto is the faster serializer and (post-#115) the faster transformer. Neither is uniformly ahead, which is the honest headline. Reproducecd benchmark
composer require --dev std-out/simple-data-objects # opt-in, needs PHP 8.4+
cd ..
php benchmark/generate.php # regenerate DTOs with strictTypes
php -d opcache.enable_cli=1 benchmark/run-sdo.php 20000
|
opcache_get_status() returns false when OPcache is disabled, so indexing it emitted warnings; capture once and check is_array() first.
- Validate iterations is positive before use (avoids division by zero). - Abort if the cache dir cannot be created, in both run-sdo and run-external. - Make the equivalence gate order-insensitive: recursively sort associative keys and encode with JSON_THROW_ON_ERROR so mismatches are meaningful.
Adds
std-out/simple-data-objects(compiled-closure DTO hydration) to the external benchmark comparison. Its author asked for this in the r/PHP thread so the numbers are reproducible on both sides rather than traded back and forth.What's in it
run-external.php- simple and nested creation, auto-detected exactly like the other libraries. If the package is not installed the section is skipped, same as jms/serializer today.run-sdo.php- a dedicated head-to-head.run-external.phponly measures hydration (where simple-data-objects leads), so this script rounds out the picture: hydration, serialization, field transforms (both theirCastattribute and theirPipemiddleware), and per-instance memory. All three transform variants (ours, their Cast, their Pipe) are verified to produce identical output for a whitespace-padded payload, so the scenarios compare equal work.generate.php- regenerates the benchmark DTOs withstrictTypesenabled. Thebin/dtoCLI does not expose that flag and transform inlining requires it.src/SimpleDataObjects/*- mirror DTOs matching the existing benchmark shapes.PHP version constraint
std-out/simple-data-objectsrequires PHP^8.4. Putting it inrequire-devwould breakcomposer installon the PHP 8.2/8.3 the benchmark still supports, so it lives undersuggestand is opt-in:cd benchmark composer require --dev std-out/simple-data-objectsThe scripts guard every call with
class_exists(), so nothing breaks when it is absent.Notes
src/is touched.createdAtis left out of the nested serialization payload on purpose: ourtoArray()keeps aDateTimeImmutablethere while theirDateTimeImmutableCastformats it back to a string, which would compare non-equivalent work.strictTypes) compiled transforms. Absolute numbers are hardware-dependent and left out on purpose; run it locally.