Skip to content

Commit 32f651b

Browse files
committed
perf: implement static translator cache to eliminate repeated file I/O
1 parent 5784096 commit 32f651b

File tree

8 files changed

+698
-167
lines changed

8 files changed

+698
-167
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.0.4] - 2026-01-05
9+
10+
### Performance
11+
- **Static Translator Cache** - Eliminates repeated file I/O across validation instances
12+
- TranslationManager now uses process-wide cached translator instance
13+
- Translation file loaded once per PHP process instead of per DataVerify instance
14+
15+
### Infrastructure
16+
- All benchmarks now run with OPcache enabled for production-realistic results
17+
818
## [1.0.3] - 2026-01-04
919
### Performance
1020
- Lazy TranslationManager initialization - 45% performance improvement

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mutation:
1010
@vendor/bin/infection --threads=4
1111

1212
benchmark:
13-
@vendor/bin/phpbench run --report=default --warmup=2 --output=csv > benchmarks/bench_results.csv
13+
@vendor/bin/phpbench run --report=default --iterations=10 --revs=1000 --warmup=2 --output=csv > benchmarks/bench_results.csv
1414

1515
p99:
1616
@cd benchmarks && php analyze_bench.php

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,11 @@ $dv->addTranslations([
244244

245245
DataVerify is designed for production with predictable sub-millisecond performance:
246246
```
247-
Simple validation: ~50μs (99% < 50μs)
248-
Complex nested: ~72μs (99% < 72μs)
249-
Batch mode (100 fields): 1.5ms
250-
Fail-fast (100 fields): 0.7ms (2x faster)
251-
Memory usage: ~4.9MB (stable)
247+
Simple validation: ~8.8μs (99% < 9μs)
248+
Complex nested: ~17.1μs (99% < 18μs)
249+
Batch mode (100 fields): 1.15ms
250+
Fail-fast (100 fields): 0.23ms (2.3x faster)
251+
Memory usage: ~4.9MB (stable)
252252
```
253253

254254
**See:** [Full benchmarks](docs/BENCHMARK.md)

benchmarks/DetailedBench.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
use Gravity\DataVerify;
4+
5+
class DetailedBench
6+
{
7+
private object $data;
8+
private DataVerify $verifier;
9+
10+
public function setUp(): void
11+
{
12+
$this->data = new stdClass();
13+
$this->data->email = "test@example.com";
14+
$this->data->age = 25;
15+
}
16+
17+
/**
18+
* @BeforeMethods({"setUp"})
19+
* @Revs(1000)
20+
* @Iterations(5)
21+
*/
22+
public function benchInstantiationOnly(): void
23+
{
24+
$verifier = new DataVerify($this->data);
25+
}
26+
27+
/**
28+
* @BeforeMethods({"setUp"})
29+
* @Revs(1000)
30+
* @Iterations(5)
31+
*/
32+
public function benchFieldCallOnly(): void
33+
{
34+
$verifier = new DataVerify($this->data);
35+
$verifier->field('email');
36+
}
37+
38+
/**
39+
* @BeforeMethods({"setUp"})
40+
* @Revs(1000)
41+
* @Iterations(5)
42+
*/
43+
public function benchFieldPlusRequired(): void
44+
{
45+
$verifier = new DataVerify($this->data);
46+
$verifier->field('email')->required;
47+
}
48+
49+
/**
50+
* @BeforeMethods({"setUp"})
51+
* @Revs(1000)
52+
* @Iterations(5)
53+
*/
54+
public function benchFieldChain(): void
55+
{
56+
$verifier = new DataVerify($this->data);
57+
$verifier->field('email')->required->email;
58+
}
59+
60+
/**
61+
* @BeforeMethods({"setUp"})
62+
* @Revs(1000)
63+
* @Iterations(5)
64+
*/
65+
public function benchTwoFields(): void
66+
{
67+
$verifier = new DataVerify($this->data);
68+
$verifier
69+
->field('email')->required->email
70+
->field('age')->required->int;
71+
}
72+
73+
/**
74+
* @BeforeMethods({"setUp"})
75+
* @Revs(1000)
76+
* @Iterations(5)
77+
*/
78+
public function benchFieldsWithArgs(): void
79+
{
80+
$verifier = new DataVerify($this->data);
81+
$verifier
82+
->field('email')->required->email
83+
->field('age')->required->int->between(18, 100);
84+
}
85+
86+
/**
87+
* @BeforeMethods({"setUp"})
88+
* @Revs(1000)
89+
* @Iterations(5)
90+
*/
91+
public function benchVerifyOnly(): void
92+
{
93+
$verifier = new DataVerify($this->data);
94+
$verifier
95+
->field('email')->required->email
96+
->field('age')->required->int->between(18, 100);
97+
98+
$verifier->verify();
99+
}
100+
101+
/**
102+
* @Revs(1000)
103+
* @Iterations(5)
104+
*/
105+
public function benchFullCycle(): void
106+
{
107+
$data = new stdClass();
108+
$data->email = "test@example.com";
109+
$data->age = 25;
110+
111+
$verifier = new DataVerify($data);
112+
$verifier
113+
->field('email')->required->email
114+
->field('age')->required->int->between(18, 100);
115+
116+
$verifier->verify();
117+
}
118+
}

benchmarks/ErrorCreationBench.php

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
use Gravity\DataVerify;
4+
5+
class ErrorCreationBench
6+
{
7+
private object $validData;
8+
private object $invalidData;
9+
10+
public function setUp(): void
11+
{
12+
$this->validData = new stdClass();
13+
$this->validData->email = "test@example.com";
14+
$this->validData->age = 25;
15+
16+
$this->invalidData = new stdClass();
17+
$this->invalidData->email = "invalid";
18+
$this->invalidData->age = -5;
19+
}
20+
21+
/**
22+
* @BeforeMethods({"setUp"})
23+
* @Revs(1000)
24+
* @Iterations(10)
25+
*/
26+
public function benchNoErrors(): void
27+
{
28+
$verifier = new DataVerify($this->validData);
29+
$verifier
30+
->field('email')->required->email
31+
->field('age')->required->int->between(18, 100);
32+
33+
$verifier->verify();
34+
}
35+
36+
/**
37+
* @BeforeMethods({"setUp"})
38+
* @Revs(1000)
39+
* @Iterations(10)
40+
*/
41+
public function benchWithErrors(): void
42+
{
43+
$verifier = new DataVerify($this->invalidData);
44+
$verifier
45+
->field('email')->required->email
46+
->field('age')->required->int->between(18, 100);
47+
48+
$verifier->verify();
49+
}
50+
51+
/**
52+
* @BeforeMethods({"setUp"})
53+
* @Revs(1000)
54+
* @Iterations(10)
55+
*/
56+
public function benchWithErrorsAndGetErrors(): void
57+
{
58+
$verifier = new DataVerify($this->invalidData);
59+
$verifier
60+
->field('email')->required->email
61+
->field('age')->required->int->between(18, 100);
62+
63+
$verifier->verify();
64+
$verifier->getErrors();
65+
}
66+
67+
/**
68+
* @BeforeMethods({"setUp"})
69+
* @Revs(1000)
70+
* @Iterations(10)
71+
*/
72+
public function benchCustomErrorMessage(): void
73+
{
74+
$data = new stdClass();
75+
$data->email = "invalid";
76+
77+
$verifier = new DataVerify($data);
78+
$verifier
79+
->field('email')
80+
->required
81+
->email
82+
->errorMessage('Custom error');
83+
84+
$verifier->verify();
85+
}
86+
87+
/**
88+
* @BeforeMethods({"setUp"})
89+
* @Revs(1000)
90+
* @Iterations(10)
91+
*/
92+
public function benchNoTranslation(): void
93+
{
94+
$verifier = new DataVerify($this->invalidData);
95+
$verifier
96+
->field('email')->required->email
97+
->field('age')->required->int->between(18, 100);
98+
99+
$verifier->verify();
100+
}
101+
102+
/**
103+
* @BeforeMethods({"setUp"})
104+
* @Revs(1000)
105+
* @Iterations(10)
106+
*/
107+
public function benchWithTranslation(): void
108+
{
109+
$verifier = new DataVerify($this->invalidData);
110+
$verifier->setLocale('fr');
111+
$verifier
112+
->field('email')->required->email
113+
->field('age')->required->int->between(18, 100);
114+
115+
$verifier->verify();
116+
}
117+
118+
}

0 commit comments

Comments
 (0)