index/src/Cache/Memcached/MemcachedBackend.php
2024-04-10 22:23:34 +00:00

109 lines
3.9 KiB
PHP

<?php
// MemcachedBackend.php
// Created: 2024-04-10
// Updated: 2024-04-10
namespace Index\Cache\Memcached;
use InvalidArgumentException;
use RuntimeException;
use Index\Cache\{ICacheBackend,ICacheProvider,ICacheProviderInfo};
use Index\Net\{EndPoint,UnixEndPoint};
/**
* Information about the memcached backend.
*/
class MemcachedBackend implements ICacheBackend {
public function isAvailable(): bool {
return extension_loaded('memcached')
|| extension_loaded('memcache');
}
/**
* Creates a memcached cache provider.
*
* Has compatibility with both the newer memcached extension and the older memcache extension.
* memcached is attempted first.
*
* @param MemcachedProviderInfo $providerInfo Memcached provider info.
* @return MemcachedProvider Memcached provider instance.
*/
public function createProvider(ICacheProviderInfo $providerInfo): ICacheProvider {
if(!($providerInfo instanceof MemcachedProviderInfo))
throw new InvalidArgumentException('$providerInfo must by of type MemcachedProviderInfo');
if(extension_loaded('memcached'))
return new MemcachedProviderModern($providerInfo);
if(extension_loaded('memcache'))
return new MemcachedProviderLegacy($providerInfo);
throw new RuntimeException('Unable to create a memcached provider.');
}
/**
* @return MemcachedProviderInfo Memcached provider info instance.
*/
public function parseDsn(string|array $dsn): ICacheProviderInfo {
if(is_string($dsn)) {
$dsn = parse_url($dsn);
if($dsn === false)
throw new InvalidArgumentException('$dsn is not a valid uri.');
}
if(!isset($dsn['host']))
throw new InvalidArgumentException('Host is missing from DSN.');
$host = $dsn['host'];
$isPool = $host === ':unix' || $host === ':pool';
$endPoints = [];
if(!$isPool) {
if(isset($dsn['port']))
$host .= ':' . $dsn['port'];
$endPoints[] = [EndPoint::parse($host), 0];
}
$endPoint = $isPool ? null : EndPoint::parse($host);
$prefixKey = str_replace('/', ':', ltrim($dsn['path'] ?? '', '/'));
parse_str(str_replace('+', '%2B', $dsn['query'] ?? ''), $query);
if(isset($query['server'])) {
if(is_string($query['server']))
$query['server'] = [$query['server']];
if(is_array($query['server']))
foreach($query['server'] as $endPoint) {
$parts = explode(';', $endPoint, 2);
$weight = count($parts) > 1 ? (int)$parts[1] : 0;
$endPoint = EndPoint::parse($parts[0]);
$endPoints[] = [$endPoint, $weight];
}
}
$persistName = isset($query['persist']) && is_string($query['persist']) ? $query['persist'] : '';
$useBinaryProto = empty($query['proto']) || $query['proto'] !== 'ascii';
if(empty($query['compress']) || !is_string($query['compress']))
$enableCompression = true;
else {
$enableCompression = strtolower($query['compress']);
$enableCompression = $enableCompression !== 'no' && $enableCompression !== 'off' && $enableCompression !== 'false' && $enableCompression !== '0';
}
if(empty($query['nodelay']) || !is_string($query['nodelay']))
$tcpNoDelay = true;
else {
$tcpNoDelay = strtolower($query['nodelay']);
$tcpNoDelay = $tcpNoDelay !== 'no' && $tcpNoDelay !== 'off' && $tcpNoDelay !== 'false' && $tcpNoDelay !== '0';
}
if(empty($endPoints))
throw new InvalidArgumentException('No servers are specified in the DSN.');
return new MemcachedProviderInfo($endPoints, $prefixKey, $persistName, $useBinaryProto, $enableCompression, $tcpNoDelay);
}
}