Skip to content

Commit 253f7d5

Browse files
committed
Add performance comparison script for integers and typed objects
- Introduced `Performance.php` to compare memory usage and execution time between arrays of scalars and typed objects. - Updated `composer.json` with a new `performance` script for running benchmarks. - Added performance disclaimer to `README.md` with guidance on use cases for typed objects vs. raw scalars. - Fixed case-sensitive file includes in `Usage` scripts (`integer.php` -> `Integer.php`).
1 parent 4cce51a commit 253f7d5

File tree

5 files changed

+170
-2
lines changed

5 files changed

+170
-2
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PHP Typed Values
22

3-
A PHP 7.4 || 8.2 library of typed value objects for common PHP data types.
3+
PHP library of typed value objects for common PHP data types.
44

55
Building blocks for a DTO's, ValueObjects, Entities, etc.
66

@@ -93,6 +93,13 @@ $profile->getHeight(); // "172.5 \ Undefined" type class
9393
- **No external dependencies** – Pure PHP implementation without requiring third‑party packages.
9494
- **Extendable** – Extendable with custom-typed values and composite value objects.
9595

96+
## Performance disclaimer
97+
98+
- **Performance** for an array of objects is about `3x` **slower** than an array of scalars;
99+
- **Memory usage** for an array of objects is about `2x` **higher**;
100+
- **Use value objects** for domain modeling, type safety, and validation boundaries;
101+
- **Use raw scalars** for high-performance loops or large-scale data processing;
102+
96103
## More information
97104

98105
See [docs/USAGE.md](docs/USAGE.md) for usage examples.

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
"test": [
5959
"./vendor/bin/pest"
6060
],
61+
"performance": [
62+
"php ./src/Usage/Performance.php 1000 && php ./src/Usage/Performance.php 10000 && php ./src/Usage/Performance.php 100000 && php ./src/Usage/Performance.php 1000000"
63+
],
6164
"usage": [
6265
"php ./src/Usage/AllTypes.php"
6366
],

src/Usage/AllTypes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
require_once 'vendor/autoload.php';
1010

11-
require_once __DIR__ . '/integer.php';
11+
require_once __DIR__ . '/Integer.php';
1212
require_once __DIR__ . '/String.php';
1313
require_once __DIR__ . '/Float.php';
1414
require_once __DIR__ . '/Boolean.php';

src/Usage/Performance.php

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require_once \dirname(__DIR__, 2) . '/vendor/autoload.php';
6+
7+
use PhpTypedValues\Integer\IntegerStandard;
8+
9+
/**
10+
* Simple console performance comparison between:
11+
* - array<int>
12+
* - array<PhpTypedValues\\Integer\\IntegerStandard>
13+
*/
14+
exit(main($argv));
15+
16+
function main(array $argv): int
17+
{
18+
$defaultN = 1_000_000;
19+
$n = parseN($argv, $defaultN);
20+
21+
echo \PHP_EOL;
22+
echo '---------------------------------------------------------' . \PHP_EOL;
23+
24+
echo 'PHP: ' . \PHP_VERSION . ' Memory limit: ' . ((string) \ini_get('memory_limit')) . ' Dataset N: ' . number_format($n) . \PHP_EOL;
25+
26+
// Ensure a clean baseline
27+
gc_collect_cycles();
28+
29+
$objects = measureObjects($n);
30+
$ints = measureInts($n);
31+
32+
echo \PHP_EOL;
33+
printf(
34+
"%-10s | time: %9.3f ms | mem: %7.2f MB\n",
35+
'ints',
36+
$ints['time_ms'],
37+
$ints['mem_delta_mb'],
38+
);
39+
printf(
40+
"%-10s | time: %9.3f ms | mem: %7.2f MB\n",
41+
'objects',
42+
$objects['time_ms'],
43+
$objects['mem_delta_mb'],
44+
);
45+
46+
// Percent difference of objects vs ints (how much more/less objects use than ints)
47+
$timePct = formatPct(pctDiff($objects['time_ms'], $ints['time_ms']));
48+
$memPct = formatPct(pctDiff($objects['mem_delta_mb'], $ints['mem_delta_mb']));
49+
50+
printf(
51+
"%-10s | time: %9s | mem: %7s\n",
52+
'diff %',
53+
$timePct,
54+
$memPct,
55+
);
56+
57+
return 0;
58+
}
59+
60+
function parseN(array $argv, int $fallback): int
61+
{
62+
// Allow: php script.php 1000000
63+
$arg = $argv[1] ?? null;
64+
if ($arg === null) {
65+
return $fallback;
66+
}
67+
68+
if (!is_numeric($arg)) {
69+
return $fallback;
70+
}
71+
72+
$n = (int) $arg;
73+
74+
return $n > 0 ? $n : $fallback;
75+
}
76+
77+
// Helpers *************************************************************************************************************
78+
79+
/** @return array{time_ms: float, mem_delta_mb: float} */
80+
function measureInts(int $n): array
81+
{
82+
$baseUsage = memory_get_usage(true);
83+
84+
$ints = [];
85+
$ints[$n - 1] = 0; // pre-allocate last index (sparse) to reduce reallocs
86+
87+
$t0 = hrtime(true);
88+
for ($i = 0; $i < $n; ++$i) {
89+
$ints[$i] = $i;
90+
}
91+
$buildElapsed = (hrtime(true) - $t0) / 1_000_000; // ms
92+
93+
// Calculate memory delta
94+
$memDeltaMb = (memory_get_usage(true) - $baseUsage) / (1024 * 1024);
95+
96+
// Keep the larger timing as total for reporting granularity
97+
$timeMs = $buildElapsed; // report build time separately below
98+
99+
// Cleanup
100+
unset($ints);
101+
gc_collect_cycles();
102+
103+
return [
104+
'time_ms' => $timeMs,
105+
'mem_delta_mb' => $memDeltaMb,
106+
];
107+
}
108+
109+
/** @return array{time_ms: float, mem_delta_mb: float} */
110+
function measureObjects(int $n): array
111+
{
112+
$baseUsage = memory_get_usage(true);
113+
114+
$objs = [];
115+
$objs[$n - 1] = null; // pre-allocate (sparse)
116+
117+
$t0 = hrtime(true);
118+
for ($i = 0; $i < $n; ++$i) {
119+
$objs[$i] = new IntegerStandard($i);
120+
}
121+
$buildElapsed = (hrtime(true) - $t0) / 1_000_000; // ms
122+
123+
$memDeltaMb = (memory_get_usage(true) - $baseUsage) / (1024 * 1024);
124+
125+
unset($objs);
126+
gc_collect_cycles();
127+
128+
return [
129+
'time_ms' => $buildElapsed,
130+
'mem_delta_mb' => $memDeltaMb,
131+
];
132+
}
133+
134+
// Percentage helpers **************************************************************************************************
135+
136+
/**
137+
* Compute percentage difference: (a / b - 1) * 100. Returns null when baseline is zero or not finite.
138+
*/
139+
function pctDiff(float $a, float $b): ?float
140+
{
141+
if ($b === 0.0 || !is_finite($a) || !is_finite($b)) {
142+
return null;
143+
}
144+
145+
return ($a / $b - 1.0) * 100.0;
146+
}
147+
148+
/**
149+
* Format percentage with sign and 1 decimal place. Returns ' n/a' when input is null.
150+
*/
151+
function formatPct(?float $pct): string
152+
{
153+
if ($pct === null) {
154+
return ' n/a';
155+
}
156+
157+
return \sprintf('%+6.1f%%', $pct);
158+
}

0 commit comments

Comments
 (0)