Runnable companion project comparing:
Requirements: PHP 8.4+, Composer, and the mbstring/xml extensions required by Laravel.
composer install
php artisan csv:sample storage/users.csv --rows=100000
php artisan benchmark:all storage/users.csv --iterations=5Or run everything in Docker — this suite followed by the XML feed benchmark:
make benchbenchmark:all compares both libraries on flat and nested hydration, a 20-item
typed collection, date casts, flat/nested/collection serialization, retained
memory, and 100,000-row streaming CSV hydration. benchmark:csv runs just the
CSV scenario.
Before measuring, it runs both libraries' cache-warming commands (sdo:warm
and data:cache-structures), then reports steady-state rows/sec and peak
memory. Run it a few times on the same machine and use the median.
php artisan xml:sample storage/offers.xml --nodes=100000
php artisan benchmark:xml storage/offers.xmlOr in Docker: make bench-xml for this benchmark alone (make bench runs it after the main suite).
benchmark:xml reads the 100,000-offer price feed written by xml:sample
(about 52 MB) and turns it into the same typed DTOs six different ways:
lazyXml()— the DTO describes the element, the file is streamed;- SimpleXML, collecting every row before hydrating (both libraries);
- SimpleXML, hydrating node by node without accumulating anything;
- a hand-rolled
XMLReaderloop with a hand-written element-to-array mapping (both libraries —spatie/laravel-datahas no XML support of its own, so this is what streaming looks like there).
Each scenario runs in its own PHP process and reports time, peak PHP heap
and peak process RSS. The two memory columns differ on purpose: the libxml
tree behind SimpleXML is allocated outside PHP's memory manager, so
memory_get_peak_usage() does not see it while the process RSS does. A
checksum over all offers confirms every scenario produced the same data.
php artisan showcase:data
php artisan sdo:typescript app/Data --output=resources/js/types/data-objects.d.tsshowcase:data demonstrates nested DTOs, typed collections, casts, pipes,
computed/hidden fields, key transformation, schema generation, and immutable
updates. sdo:typescript generates a TypeScript contract from the same DTO
metadata.
For a fair comparison, commit composer.lock and record the PHP/Laravel/
package versions and hardware alongside the numbers.