acc-check-caching-strategy
Caching Strategy Analysis
Analyze PHP code for caching opportunities and issues.
Detection Patterns
1. Missing Cache Opportunities
// CACHEABLE: Repeated expensive computation
public function getExchangeRate(string $currency): float
{
return $this->api->fetchRate($currency); // API call each time
}
// CACHEABLE: Repeated database query
public function getSettings(): array
{
return $this->repository->findAll(); // Same query repeatedly
}
// CACHEABLE: Configuration that rarely changes
public function getFeatureFlags(): array
{
return $this->configLoader->load(); // File read each request
}
2. Cache Invalidation Issues
// STALE DATA: No invalidation
$cache->set('user_' . $id, $user, 3600);
// Later: user updated but cache not cleared
// STALE DATA: Time-based only
$cache->set('products', $products, 86400);
// Products change but cache lives for 24h
// RACE CONDITION: Invalidate before update
$this->cache->delete('user_' . $id);
$this->repository->update($user);
// Another request may cache old data between these lines
3. Over-Caching
// OVER-CACHED: User-specific data with long TTL
$cache->set('user_dashboard_' . $userId, $data, 86400);
// User dashboard may need fresh data
// OVER-CACHED: Rapidly changing data
$cache->set('stock_count_' . $productId, $count, 3600);
// Stock changes frequently
// OVER-CACHED: Huge cache entries
$cache->set('all_products', $allProducts); // 10MB cache entry
4. Cache Stampede
// STAMPEDE: Many requests rebuild cache simultaneously
public function getData(): array
{
$data = $this->cache->get('key');
if (!$data) {
$data = $this->expensiveOperation(); // All concurrent requests hit this
$this->cache->set('key', $data, 3600);
}
return $data;
}
// FIXED: Lock during rebuild
public function getData(): array
{
$data = $this->cache->get('key');
if (!$data) {
$lock = $this->lockFactory->createLock('key_rebuild');
if ($lock->acquire()) {
$data = $this->expensiveOperation();
$this->cache->set('key', $data, 3600);
$lock->release();
} else {
$data = $this->cache->get('key'); // Wait for other process
}
}
return $data;
}
5. Wrong Cache Key
// BAD: Missing important parameters
$cache->get('user_data'); // Same for all users?
// BAD: Too specific
$cache->get('user_' . $id . '_' . $requestId); // Never hits
// BAD: Collision risk
$cache->get(md5($query)); // Different queries may collide
// GOOD: Meaningful, unique key
$cache->get(sprintf('user:%d:profile:v1', $userId));
6. Cache Storage Issues
// PROBLEM: Storing large objects
$cache->set('report', $largeReport); // 50MB serialized
// PROBLEM: Storing non-serializable
$cache->set('connection', $pdoConnection); // Can't serialize
// PROBLEM: Storing closures
$cache->set('callback', function() { }); // Fails
7. TTL Issues
// TOO SHORT: Cache overhead exceeds benefit
$cache->set('data', $data, 1); // 1 second TTL
// TOO LONG: Stale data risk
$cache->set('exchange_rates', $rates, 604800); // 1 week
// NO TTL: Memory leak risk
$cache->set('data', $data); // Never expires
// FIXED: Appropriate TTL
$cache->set('exchange_rates', $rates, 300); // 5 minutes
8. Cache Warming
// COLD START: First request is slow
// No warming strategy, first user waits
// BETTER: Warm cache on deploy/schedule
public function warmCache(): void
{
$this->cache->set('config', $this->loadConfig());
$this->cache->set('categories', $this->loadCategories());
}
Grep Patterns
# API calls without cache
Grep: "->request\(|->get\(|->fetch\(" --glob "**/*.php"
# Repository calls that could be cached
Grep: "Repository->find|Repository->get" --glob "**/*.php"
# Cache operations
Grep: "->cache->|Cache::|redis->|memcache" --glob "**/*.php"
# Missing TTL
Grep: "->set\([^,]+,[^,]+\)\s*;" --glob "**/*.php"
Caching Patterns
Read-Through Cache
public function get(string $key, callable $loader, int $ttl = 3600): mixed
{
$value = $this->cache->get($key);
if ($value === null) {
$value = $loader();
$this->cache->set($key, $value, $ttl);
}
return $value;
}
Write-Through Cache
public function update(Entity $entity): void
{
$this->repository->save($entity);
$this->cache->set('entity:' . $entity->getId(), $entity);
}
Cache-Aside with Locking
public function getWithLock(string $key, callable $loader): mixed
{
$value = $this->cache->get($key);
if ($value !== null) {
return $value;
}
$lock = $this->lockFactory->createLock($key);
if ($lock->acquire()) {
try {
$value = $loader();
$this->cache->set($key, $value);
} finally {
$lock->release();
}
} else {
usleep(100000);
return $this->getWithLock($key, $loader);
}
return $value;
}
Severity Classification
| Pattern | Severity |
|---|---|
| Cache stampede risk | π΄ Critical |
| Missing invalidation | π Major |
| Missing cache for hot path | π Major |
| Wrong cache key | π Major |
| Overly long TTL | π‘ Minor |
| Over-caching user data | π‘ Minor |
Output Format
### Caching Issue: [Description]
**Severity:** π΄/π /π‘
**Location:** `file.php:line`
**Type:** [Missing Cache|Invalidation|Stampede|...]
**Issue:**
[Description of the caching problem]
**Code:**
```php
// Current code
Fix:
// With proper caching
Expected Improvement: Response time: 500ms β 5ms (on cache hit) Database load: 1000 QPS β 100 QPS
## When This Is Acceptable
- **Premature caching** β Adding cache before proving a performance bottleneck exists creates complexity without benefit
- **Frequently changing data** β Data that changes on every request (e.g., real-time prices) shouldn't be cached
- **Development environment** β Missing cache in dev/test environments is intentional
### False Positive Indicators
- Code is in early development stage without performance profiling
- Data has TTL < 1 second or changes per-request
- Cache is disabled by environment configuration (dev/test)
More from dykyi-roman/awesome-claude-code
psr-overview-knowledge
PHP Standards Recommendations (PSR) overview knowledge base. Provides comprehensive reference for all accepted PSRs including PSR-1,3,4,6,7,11,12,13,14,15,16,17,18,20. Use for PSR selection decisions and compliance audits.
22detect-code-smells
Detects code smells in PHP codebases. Identifies God Class, Feature Envy, Data Clumps, Long Parameter List, Long Method, Primitive Obsession, Message Chains, Inappropriate Intimacy. Generates actionable reports with refactoring recommendations.
15clean-arch-knowledge
Clean Architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Clean Architecture and Hexagonal Architecture audits.
15ddd-knowledge
DDD architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Domain-Driven Design audits.
14testing-knowledge
Testing knowledge base for PHP 8.4 projects. Provides testing pyramid, AAA pattern, naming conventions, isolation principles, DDD testing guidelines, and PHPUnit patterns.
12bug-root-cause-finder
Root cause analysis methods for PHP bugs. Provides 5 Whys technique, fault tree analysis, git bisect guidance, and stack trace parsing.
12