Currently, the Lombok::call() method performs reflection-based lookups on every invocation of getter/setter methods through the __call() magic method. While the initial configuration is cached per object instance, the method resolution still requires traversing the accessor maps on each call. This could potentially impact performance in high-throughput scenarios.
Current Behavior
public static function call(object $targetObj, string $methodName, array $args)
{
$objectConfig = static::construct($targetObj); // This is cached
// But these lookups happen on every call:
$getter = $objectConfig->getGetter($methodName);
if ($getter \!== null) {
return $getter->getValue($targetObj);
}
$item = $objectConfig->getSetter($methodName);
if ($item \!== null) {
$item->setValue($targetObj, $args[0]);
return $targetObj;
}
throw new \BadMethodCallException(...);
}
Proposed Solution
Implement a multi-level caching strategy:
- Method Resolution Cache: Cache the mapping of method names to their accessor type (getter/setter) and associated ReflectionProperty
- Per-Class Cache: Since all instances of a class share the same method definitions, cache at the class level
- Benchmark-Driven Decision: Create benchmarks to measure if caching provides real benefits or just adds complexity
Testing Requirements
1. Performance Benchmarks
Create benchmarks to measure:
- Baseline performance without caching
- Performance with different caching strategies
- Memory overhead of caching
- Cache hit/miss ratios in typical usage
2. Correctness Tests
- Verify cache invalidation when classes are modified (dev environment)
- Test memory cleanup for short-lived objects
- Ensure thread safety if applicable
- Test behavior with class inheritance
3. Memory Usage Tests
- Monitor memory usage with large numbers of different classes
- Verify no memory leaks with long-running processes
- Test cache size limits if implemented
Success Criteria
- Performance: At least 20% improvement in getter/setter call performance for repeated calls
- Memory: Cache overhead should not exceed 1MB for typical applications (1000 entities)
- Complexity: Implementation should not significantly complicate the codebase
- BC: Must maintain backward compatibility
Risks and Considerations
- Over-optimization: Caching might not provide significant benefits if reflection is already fast enough
- Memory overhead: Cache could consume more memory than it saves in CPU time
- Cache invalidation: Handling dynamic class modifications (though rare in production)
- Complexity: Added complexity might make the code harder to maintain
Decision Points
Before implementation, benchmarks should answer:
- Is the current performance actually a bottleneck?
- What's the typical method call pattern in real applications?
- Does caching provide measurable benefits?
- What's the optimal cache strategy for typical use cases?
Currently, the
Lombok::call()method performs reflection-based lookups on every invocation of getter/setter methods through the__call()magic method. While the initial configuration is cached per object instance, the method resolution still requires traversing the accessor maps on each call. This could potentially impact performance in high-throughput scenarios.Current Behavior
Proposed Solution
Implement a multi-level caching strategy:
Testing Requirements
1. Performance Benchmarks
Create benchmarks to measure:
2. Correctness Tests
3. Memory Usage Tests
Success Criteria
Risks and Considerations
Decision Points
Before implementation, benchmarks should answer: