From 67ebf4d71ee882875978f9368aaca079fdff6d70 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Thu, 21 Aug 2025 16:11:20 -0400 Subject: [PATCH 1/4] Add support for Memcached client options in MemcachedEngine --- docs/class-memcached-engine.md | 24 ++++++++++++---- src/Factory.php | 4 +-- src/Psr16/MemcachedEngine.php | 51 +++++++++++++++++++++++++++++----- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/docs/class-memcached-engine.md b/docs/class-memcached-engine.md index 46cfe63..30831cb 100644 --- a/docs/class-memcached-engine.md +++ b/docs/class-memcached-engine.md @@ -5,30 +5,44 @@ This class uses the Memcached as the cache engine. ## Defining the Servers The constructor expects an array of servers. -Each server is an item in the array with the following format: +Each server can be provided in one of the following formats: ```php $servers = [ 'localhost:11211', -] + ['host.example', 11211], +]; +``` + +You can also pass Memcached client options (no need to pass a Memcached instance). Options can be provided as an associative array where the keys are Memcached option constants or their string names: + +```php +$options = [ + \Memcached::OPT_DISTRIBUTION => \Memcached::DISTRIBUTION_CONSISTENT, + \Memcached::OPT_LIBKETAMA_COMPATIBLE => true, + \Memcached::OPT_REMOVE_FAILED_SERVERS => true, + \Memcached::OPT_CONNECT_TIMEOUT => 100, // ms + // Or using string keys: + 'OPT_CONNECT_TIMEOUT' => 100, +]; ``` ## PSR-16 Constructor ```php -$cache = new \ByJG\Cache\Psr16\MemcachedEngine($servers) +$cache = new \ByJG\Cache\Psr16\MemcachedEngine($servers, null, $options); ``` ## PSR-6 Constructor ```php -$cachePool = \ByJG\Cache\Factory::createMemcachedPool($servers) +$cachePool = \ByJG\Cache\Factory::createMemcachedPool($servers, 10, null, $options) ``` or ```php -$cachePool = new \ByJG\Cache\Psr6\CachePool(new \ByJG\Cache\Psr16\MemcachedEngine($servers)); +$cachePool = new \ByJG\Cache\Psr6\CachePool(new \ByJG\Cache\Psr16\MemcachedEngine($servers, null, $options)); ``` diff --git a/src/Factory.php b/src/Factory.php index 61c6148..f6a2c6d 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -54,10 +54,10 @@ public static function createArrayPool(int $bufferSize = 10, ?LoggerInterface $l ); } - public static function createMemcachedPool(?array $servers = null, int $bufferSize = 10, ?LoggerInterface $logger = null): CachePool + public static function createMemcachedPool(?array $servers = null, int $bufferSize = 10, ?LoggerInterface $logger = null, ?array $options = null): CachePool { return new CachePool( - new MemcachedEngine($servers, $logger), + new MemcachedEngine($servers, $logger, $options), $bufferSize ); } diff --git a/src/Psr16/MemcachedEngine.php b/src/Psr16/MemcachedEngine.php index 117cc38..c8b72d2 100644 --- a/src/Psr16/MemcachedEngine.php +++ b/src/Psr16/MemcachedEngine.php @@ -25,7 +25,9 @@ class MemcachedEngine extends BaseCacheEngine implements AtomicOperationInterfac protected ?array $servers = null; - public function __construct(?array $servers = null, $logger = null) + protected ?array $options = null; + + public function __construct(?array $servers = null, $logger = null, ?array $options = null) { $this->servers = (array)$servers; if (is_null($servers)) { @@ -34,10 +36,12 @@ public function __construct(?array $servers = null, $logger = null) ]; } - $this->logger = $logger; - if (is_null($logger)) { + $this->logger = $logger instanceof LoggerInterface ? $logger : null; + if (is_null($this->logger)) { $this->logger = new NullLogger(); } + + $this->options = $options; } /** @@ -58,13 +62,46 @@ protected function lazyLoadMemCachedServers(): void { if (is_null($this->memCached)) { $this->memCached = new Memcached(); + + // Apply options if provided + if (is_array($this->options)) { + foreach ($this->options as $opt => $val) { + // Accept both numeric keys (constants) and string keys like 'OPT_CONNECT_TIMEOUT' + if (is_string($opt) && defined(Memcached::class . '::' . $opt)) { + $opt = constant(Memcached::class . '::' . $opt); + } + if (is_int($opt)) { + $this->memCached->setOption($opt, $val); + } + } + } + + // Add servers. Accept formats: + // - ['host:port', ...] + // - [['host', port], ...] foreach ($this->servers as $server) { - $data = explode(":", $server); - $this->memCached->addServer($data[0], intval($data[1])); + $host = null; + $port = null; + if (is_string($server)) { + $data = explode(":", $server); + $host = $data[0] ?? '127.0.0.1'; + $port = isset($data[1]) ? intval($data[1]) : 11211; + } elseif (is_array($server) && isset($server[0])) { + $host = (string)$server[0]; + $port = isset($server[1]) ? intval($server[1]) : 11211; + } + + if ($host === null || $port === null) { + continue; // skip invalid entry + } + + $this->memCached->addServer($host, $port); + // Server health check $stats = $this->memCached->getStats(); - if (!isset($stats[$server]) || $stats[$server]['pid'] === -1) { - throw new StorageErrorException("Memcached server $server is down"); + $key = $host . ':' . $port; + if (!isset($stats[$key]) || (isset($stats[$key]['pid']) && $stats[$key]['pid'] === -1)) { + throw new StorageErrorException("Memcached server {$key} is down"); } } } From ee5f82925c08db2dfdf973416653f4f122c47c97 Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Thu, 21 Aug 2025 16:40:34 -0400 Subject: [PATCH 2/4] Add support for Memcached client options in MemcachedEngine --- src/Psr16/MemcachedEngine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Psr16/MemcachedEngine.php b/src/Psr16/MemcachedEngine.php index c8b72d2..e1eb364 100644 --- a/src/Psr16/MemcachedEngine.php +++ b/src/Psr16/MemcachedEngine.php @@ -92,6 +92,7 @@ protected function lazyLoadMemCachedServers(): void } if ($host === null || $port === null) { + $this->logger->warning("[Memcached] Invalid server configuration skipped: " . json_encode($server)); continue; // skip invalid entry } From 253542efe35de732dd34cc5f1868c4b2a29cf29e Mon Sep 17 00:00:00 2001 From: Joao M Date: Fri, 22 Aug 2025 08:00:56 -0500 Subject: [PATCH 3/4] Update src/Psr16/MemcachedEngine.php --- src/Psr16/MemcachedEngine.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Psr16/MemcachedEngine.php b/src/Psr16/MemcachedEngine.php index e1eb364..8e2ea56 100644 --- a/src/Psr16/MemcachedEngine.php +++ b/src/Psr16/MemcachedEngine.php @@ -72,6 +72,8 @@ protected function lazyLoadMemCachedServers(): void } if (is_int($opt)) { $this->memCached->setOption($opt, $val); + } else { + $this->logger->warning("[Memcached] Failed to set option {$opt} with value " . json_encode($val)); } } } From 9620942ea2799238f9c8450c7cedc943b83ec23f Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Sat, 23 Aug 2025 18:05:30 -0400 Subject: [PATCH 4/4] GitHub Actions --- .github/workflows/phpunit.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 82e2934..65380c9 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -49,5 +49,6 @@ jobs: with: folder: php project: ${{ github.event.repository.name }} - secrets: inherit + secrets: + DOC_TOKEN: ${{ secrets.DOC_TOKEN }}