Common issues and their solutions.
- Installation Issues
- Storage Backend Issues
- Performance Issues
- Data Issues
- Laravel Integration Issues
- Debugging Tips
Problem:
Your requirements could not be resolved to an installable set of packages.
Solution:
# Update composer
composer self-update
# Clear cache
composer clear-cache
# Try again
composer require iprodev/php-easycacheProblem:
php-easycache requires php ^8.1 but your PHP version (7.4) does not satisfy that requirement.
Solution: Upgrade to PHP 8.1 or higher:
# Ubuntu/Debian
sudo apt-get install php8.1
# Check version
php -vProblem:
RuntimeException: APCu extension is not available
Solution:
# Install APCu extension
sudo apt-get install php-apcu # Ubuntu/Debian
sudo yum install php-apcu # CentOS/RHEL
# Verify installation
php -m | grep apcu
# Enable for CLI (if needed)
# Edit php.ini and add:
apc.enable_cli=1Verify:
<?php
phpinfo(); // Look for APCu sectionProblem:
RuntimeException: APCu is not enabled
Solution: Edit php.ini:
[apcu]
extension=apcu.so
apc.enabled=1
apc.enable_cli=1 ; For CLI scripts
apc.shm_size=128M ; Shared memory sizeRestart web server:
sudo systemctl restart php8.1-fpm
sudo systemctl restart apache2 # or nginxProblem:
RedisException: Connection refused
Solution:
- Check if Redis is running:
redis-cli ping
# Should return: PONG- Start Redis if not running:
sudo systemctl start redis
sudo systemctl enable redis # Start on boot- Check Redis configuration:
# Edit /etc/redis/redis.conf
bind 127.0.0.1
port 6379
protected-mode yes- Test connection:
$redis = new Redis();
if ($redis->connect('127.0.0.1', 6379)) {
echo "Connected!";
} else {
echo "Failed to connect";
}Problem:
RedisException: NOAUTH Authentication required
Solution:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('your_password_here');
$storage = new RedisStorage($redis);Problem:
RuntimeException: Unable to create cache directory: /var/cache/app
Solution:
- Create directory with proper permissions:
sudo mkdir -p /var/cache/app
sudo chown www-data:www-data /var/cache/app
sudo chmod 770 /var/cache/app- Or use a writable directory:
$storage = new FileStorage(
sys_get_temp_dir() . '/mycache'
);- Check SELinux (if enabled):
# Check SELinux status
getenforce
# Allow PHP to write to cache directory
sudo chcon -R -t httpd_cache_t /var/cache/appProblem:
Warning: fwrite(): write of XXX bytes failed with errno=28 No space left on device
Solution:
- Check disk space:
df -h- Clear old cache:
$cache->clear();- Set up automatic cleanup:
# Add to crontab
0 2 * * * php /path/to/cleanup.phpcleanup.php:
<?php
$cache->prune(); // For PDO
$cache->clear(); // Or clear allProblem:
PDOException: SQLSTATE[42S02]: Base table or view not found
Solution:
$storage = new PdoStorage($pdo, 'easycache');
$storage->ensureTable(); // Create tableProblem:
PDOException: SQLSTATE[HY000] [2002] Connection refused
Solution:
- Check database is running:
# MySQL
sudo systemctl status mysql
# PostgreSQL
sudo systemctl status postgresql- Check connection parameters:
try {
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=cache;charset=utf8mb4',
'username',
'password',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
echo "Connected!";
} catch (PDOException $e) {
echo "Failed: " . $e->getMessage();
}Problem: Cache reads are slower than expected.
Diagnosis:
$start = microtime(true);
$value = $cache->get('key');
$time = (microtime(true) - $start) * 1000;
echo "Read took: {$time}ms";Solutions:
- Add APCu as first tier:
$cache = new MultiTierCache([
new ApcuStorage(), // Add this
new RedisStorage($redis),
new FileStorage('/cache')
]);- Reduce payload size with compression:
$cache = new MultiTierCache(
[$storage],
new JsonSerializer(), // Smaller than Native
new GzipCompressor(3) // Compress large data
);- Use file sharding:
$storage = new FileStorage('/cache', '.cache', 2); // Enable shardingProblem: Too many cache misses.
Diagnosis:
$hits = 0;
$misses = 0;
for ($i = 0; $i < 1000; $i++) {
$value = $cache->get("key_{$i}");
if ($value !== null) {
$hits++;
} else {
$misses++;
}
}
$hitRate = $hits / ($hits + $misses);
echo "Hit rate: " . ($hitRate * 100) . "%";Solutions:
- Increase TTL:
$cache->set('key', $value, 3600); // 1 hour instead of 5 minutes- Use SWR for frequently accessed data:
$value = $cache->getOrSetSWR(
'key',
fn() => loadData(),
300, // TTL
60, // SWR
1800 // Stale-if-error
);- Warm up cache:
// During deployment or cron
$cache->set('popular_data', loadPopularData(), 3600);Problem:
PHP Warning: apcu_store(): Unable to allocate memory for pool
Solution:
- Increase APCu memory:
; php.ini
apc.shm_size=256M ; Increase from default 32M- Clear APCu:
# CLI
php -r "apcu_clear_cache();"
# Or in code
$storage = new ApcuStorage();
$storage->clear();- Use compression:
$cache = new MultiTierCache(
[new ApcuStorage()],
new JsonSerializer(),
new GzipCompressor(5) // Reduce memory usage
);Problem: Cache returns corrupted or unexpected data.
Diagnosis:
$raw = $storage->get('key');
echo "Raw data: " . bin2hex(substr($raw, 0, 20));Solutions:
- Clear corrupted cache:
$cache->delete('corrupted_key');
// Or
$cache->clear();- Check serializer compatibility:
// If you changed serializer, old data might be incompatible
$cache->clear(); // Clear old data- Verify data before caching:
if (is_array($data) && isset($data['required_field'])) {
$cache->set('key', $data, 3600);
}Problem: Cache returns old data even though it should be updated.
Solutions:
- Invalidate on update:
function updateUser($id, $data) {
$db->update('users', $data, ['id' => $id]);
$cache->delete("user_{$id}"); // Invalidate
}- Use shorter TTL:
$cache->set('key', $value, 300); // 5 minutes instead of 1 hour- Use version keys:
$version = $cache->get('data_version') ?? 1;
$key = "data_v{$version}";
$data = $cache->get($key);
// When data changes:
$cache->set('data_version', $version + 1);Problem:
JsonException: Malformed UTF-8 characters
Solution:
- Switch to NativeSerializer:
$cache = new MultiTierCache(
[$storage],
new NativeSerializer(), // More forgiving
$compressor
);- Clean data before caching:
$cleanData = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
$cache->set('key', $cleanData, 3600);Problem: Objects lose their class after retrieval.
Solution:
Use NativeSerializer (not JsonSerializer) for objects:
$cache = new MultiTierCache(
[$storage],
new NativeSerializer(), // Preserves objects
$compressor
);
class User {
public $id;
public $name;
}
$user = new User();
$cache->set('user', $user, 3600);
$cached = $cache->get('user');
// $cached is still a User objectProblem:
Facade [EasyCache] does not exist
Solution:
- Clear Laravel caches:
php artisan config:clear
php artisan cache:clear
php artisan clear-compiled- Check package discovery:
composer dump-autoload- Manual registration (if needed):
// config/app.php
'providers' => [
Iprodev\EasyCache\Laravel\EasyCacheServiceProvider::class,
],
'aliases' => [
'EasyCache' => Iprodev\EasyCache\Laravel\Facades\EasyCache::class,
],Problem: Config file missing after installation.
Solution:
php artisan vendor:publish --tag=easycache-config --forceProblem: EasyCache interferes with Laravel's built-in cache.
Solution: Use different cache for EasyCache:
// config/easycache.php
'redis' => [
'database' => 1, // Use DB 1 for EasyCache
],
// Laravel uses DB 0 by defaultuse Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
$logger = new Logger('cache');
$logger->pushHandler(new StreamHandler('/var/log/cache.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
$cache = new MultiTierCache($tiers, $serializer, $compressor, 3600, $logger);class DebugCache
{
private $cache;
public function get($key)
{
$start = microtime(true);
$value = $this->cache->get($key);
$time = (microtime(true) - $start) * 1000;
error_log(sprintf(
"CACHE GET: key=%s, found=%s, time=%.2fms",
$key,
$value !== null ? 'yes' : 'no',
$time
));
return $value;
}
}// List all keys (development only!)
function listCacheKeys(FileStorage $storage): array
{
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($storage->getPath())
);
$keys = [];
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'cache') {
$keys[] = $file->getBasename('.cache');
}
}
return $keys;
}function testCache($cache): void
{
echo "Testing cache...\n";
// Test set
$ok = $cache->set('test_key', 'test_value', 60);
echo "Set: " . ($ok ? 'OK' : 'FAIL') . "\n";
// Test get
$value = $cache->get('test_key');
echo "Get: " . ($value === 'test_value' ? 'OK' : 'FAIL') . "\n";
// Test has
$exists = $cache->has('test_key');
echo "Has: " . ($exists ? 'OK' : 'FAIL') . "\n";
// Test delete
$ok = $cache->delete('test_key');
echo "Delete: " . ($ok ? 'OK' : 'FAIL') . "\n";
// Test get after delete
$value = $cache->get('test_key');
echo "Get after delete: " . ($value === null ? 'OK' : 'FAIL') . "\n";
}function getCacheSize(string $path): array
{
$size = 0;
$count = 0;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path)
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$size += $file->getSize();
$count++;
}
}
return [
'size' => $size,
'size_mb' => round($size / 1024 / 1024, 2),
'files' => $count
];
}If you're still having issues:
-
Check the logs:
/var/log/cache.log(if configured)/var/log/php-fpm/error.log/var/log/apache2/error.log
-
Enable debug mode:
error_reporting(E_ALL);
ini_set('display_errors', 1);- Create a minimal test case:
<?php
require 'vendor/autoload.php';
use Iprodev\EasyCache\Cache\MultiTierCache;
use Iprodev\EasyCache\Storage\FileStorage;
$cache = new MultiTierCache([
new FileStorage('/tmp/test_cache')
]);
$cache->set('test', 'value', 60);
echo $cache->get('test'); // Should output: value- Report the issue:
- GitHub Issues
- Include: PHP version, OS, error messages, code example
| Error | Cause | Solution |
|---|---|---|
RuntimeException: APCu extension is not available |
APCu not installed | Install php-apcu |
RuntimeException: Unable to create cache directory |
Permission denied | Fix directory permissions |
RedisException: Connection refused |
Redis not running | Start Redis service |
InvalidArgument: Illegal cache key |
Invalid key format | Use only A-Za-z0-9_. |
JsonException: Malformed UTF-8 |
Invalid JSON data | Use NativeSerializer |
PDOException: Table not found |
Table doesn't exist | Call ensureTable() |
For more information, see: