connect(); } public function getClient(): Redis { if (! $this->isConnected()) { $this->reconnect(); } return $this->client; } public function getDatabase(): int { return $this->config->database; } public function getName(): string { return $this->name; } public function isConnected(): bool { if (! $this->connected) { return false; } try { return $this->client->ping() === '+PONG'; } catch (RedisException) { $this->connected = false; return false; } } public function reconnect(): void { $this->connected = false; $this->connect(); } private function connect(): void { if (! extension_loaded('redis')) { throw new RedisConnectionException( "Redis extension is not loaded. Please install php-redis extension or use alternative cache drivers." ); } $this->client = new Redis(); try { // Connect to Redis $success = $this->client->connect( $this->config->host, $this->config->port, $this->config->timeout, null, // reserved 0, // retry_interval $this->config->readWriteTimeout ); if (! $success) { throw new RedisConnectionException("Failed to connect to Redis server"); } // Authenticate if a password is provided if ($this->client->auth($this->config->password) === false) { throw new RedisConnectionException("Redis authentication failed"); } // Select database if ($this->config->database > 0) { if ($this->client->select($this->config->database) === false) { throw new RedisConnectionException("Failed to select Redis database {$this->config->database}"); } } // Set additional options foreach ($this->config->options as $option => $value) { $this->client->setOption($option, $value); } $this->connected = true; } catch (RedisException $e) { $this->connected = false; throw new RedisConnectionException( "Failed to connect to Redis ({$this->name}): " . $e->getMessage() . " with Host: {$this->config->host} and Password: {$this->config->password}", previous: $e ); } } public function flush(): void { if (! $this->isConnected()) { $this->reconnect(); } $this->client->flushDB(); } public function get(string $key): string|false { if (! $this->isConnected()) { $this->reconnect(); } return $this->client->get($key); } public function set(string $key, string $value, ?int $ttl = null): bool { if (! $this->isConnected()) { $this->reconnect(); } if ($ttl === null) { return $this->client->set($key, $value); } return $this->client->setex($key, $ttl, $value); } public function delete(string ...$keys): int { if (empty($keys)) { return 0; } if (! $this->isConnected()) { $this->reconnect(); } return $this->client->del($keys); } public function exists(string ...$keys): int { if (empty($keys)) { return 0; } if (! $this->isConnected()) { $this->reconnect(); } return $this->client->exists(...$keys); } public function ttl(string $key): int { if (! $this->isConnected()) { $this->reconnect(); } return $this->client->ttl($key); } public function expire(string $key, int $seconds): bool { if (! $this->isConnected()) { $this->reconnect(); } return $this->client->expire($key, $seconds); } public function incr(string $key, int $by = 1): int { if (! $this->isConnected()) { $this->reconnect(); } return $by === 1 ? $this->client->incr($key) : $this->client->incrBy($key, $by); } public function decr(string $key, int $by = 1): int { if (! $this->isConnected()) { $this->reconnect(); } return $by === 1 ? $this->client->decr($key) : $this->client->decrBy($key, $by); } public function mGet(array $keys): array { if (empty($keys)) { return []; } if (! $this->isConnected()) { $this->reconnect(); } return $this->client->mGet($keys); } public function mSet(array $keyValuePairs): bool { if (empty($keyValuePairs)) { return true; } if (! $this->isConnected()) { $this->reconnect(); } return $this->client->mSet($keyValuePairs); } public function command(string $command, string|int ...$arguments): mixed { if (! $this->isConnected()) { $this->reconnect(); } return $this->client->rawCommand($command, ...$arguments); } /** * Close the connection when the object is destroyed */ public function __destruct() { if ($this->connected && isset($this->client)) { try { $this->client->close(); } catch (RedisException) { // Ignore disconnection errors during destruction } } } }