3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Cache\Storage\Adapter
;
14 use Zend\Cache\Exception
;
15 use Zend\Cache\Storage\AvailableSpaceCapableInterface
;
16 use Zend\Cache\Storage\Capabilities
;
17 use Zend\Cache\Storage\FlushableInterface
;
18 use Zend\Cache\Storage\TotalSpaceCapableInterface
;
20 class WinCache
extends AbstractAdapter
implements
21 AvailableSpaceCapableInterface
,
23 TotalSpaceCapableInterface
28 * @param array|Traversable|WinCacheOptions $options
29 * @throws Exception\ExceptionInterface
31 public function __construct($options = null)
33 if (!extension_loaded('wincache')) {
34 throw new Exception\
ExtensionNotLoadedException("WinCache extension is not loaded");
37 $enabled = ini_get('wincache.ucenabled');
38 if (PHP_SAPI
== 'cli') {
39 $enabled = $enabled && (bool) ini_get('wincache.enablecli');
43 throw new Exception\
ExtensionNotLoadedException(
44 "WinCache is disabled - see 'wincache.ucenabled' and 'wincache.enablecli'"
48 parent
::__construct($options);
56 * @param array|Traversable|WinCacheOptions $options
60 public function setOptions($options)
62 if (!$options instanceof WinCacheOptions
) {
63 $options = new WinCacheOptions($options);
66 return parent
::setOptions($options);
72 * @return WinCacheOptions
75 public function getOptions()
77 if (!$this->options
) {
78 $this->setOptions(new WinCacheOptions());
80 return $this->options
;
83 /* TotalSpaceCapableInterface */
86 * Get total space in bytes
90 public function getTotalSpace()
92 $mem = wincache_ucache_meminfo();
93 return $mem['memory_total'];
96 /* AvailableSpaceCapableInterface */
99 * Get available space in bytes
103 public function getAvailableSpace()
105 $mem = wincache_ucache_meminfo();
106 return $mem['memory_free'];
109 /* FlushableInterface */
112 * Flush the whole storage
116 public function flush()
118 return wincache_ucache_clear();
124 * Internal method to get an item.
126 * @param string $normalizedKey
127 * @param bool $success
128 * @param mixed $casToken
129 * @return mixed Data on success, null on failure
130 * @throws Exception\ExceptionInterface
132 protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null)
134 $options = $this->getOptions();
135 $namespace = $options->getNamespace();
136 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
137 $internalKey = $prefix . $normalizedKey;
138 $result = wincache_ucache_get($internalKey, $success);
150 * Internal method to get multiple items.
152 * @param array $normalizedKeys
153 * @return array Associative array of keys and values
154 * @throws Exception\ExceptionInterface
156 protected function internalGetItems(array & $normalizedKeys)
158 $options = $this->getOptions();
159 $namespace = $options->getNamespace();
160 if ($namespace === '') {
161 return wincache_ucache_get($normalizedKeys);
164 $prefix = $namespace . $options->getNamespaceSeparator();
165 $internalKeys = array();
166 foreach ($normalizedKeys as $normalizedKey) {
167 $internalKeys[] = $prefix . $normalizedKey;
170 $fetch = wincache_ucache_get($internalKeys);
172 // remove namespace prefix
173 $prefixL = strlen($prefix);
175 foreach ($fetch as $internalKey => & $value) {
176 $result[substr($internalKey, $prefixL)] = & $value;
183 * Internal method to test if an item exists.
185 * @param string $normalizedKey
187 * @throws Exception\ExceptionInterface
189 protected function internalHasItem(& $normalizedKey)
191 $options = $this->getOptions();
192 $namespace = $options->getNamespace();
193 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
194 return wincache_ucache_exists($prefix . $normalizedKey);
198 * Get metadata of an item.
200 * @param string $normalizedKey
201 * @return array|bool Metadata on success, false on failure
202 * @throws Exception\ExceptionInterface
204 protected function internalGetMetadata(& $normalizedKey)
206 $options = $this->getOptions();
207 $namespace = $options->getNamespace();
208 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
209 $internalKey = $prefix . $normalizedKey;
211 $info = wincache_ucache_info(true, $internalKey);
212 if (isset($info['ucache_entries'][1])) {
213 $metadata = $info['ucache_entries'][1];
214 $this->normalizeMetadata($metadata);
224 * Internal method to store an item.
226 * @param string $normalizedKey
227 * @param mixed $value
229 * @throws Exception\ExceptionInterface
231 protected function internalSetItem(& $normalizedKey, & $value)
233 $options = $this->getOptions();
234 $namespace = $options->getNamespace();
235 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
236 $internalKey = $prefix . $normalizedKey;
237 $ttl = $options->getTtl();
239 if (!wincache_ucache_set($internalKey, $value, $ttl)) {
240 $type = is_object($value) ?
get_class($value) : gettype($value);
241 throw new Exception\
RuntimeException(
242 "wincache_ucache_set('{$internalKey}', <{$type}>, {$ttl}) failed"
250 * Internal method to store multiple items.
252 * @param array $normalizedKeyValuePairs
253 * @return array Array of not stored keys
254 * @throws Exception\ExceptionInterface
256 protected function internalSetItems(array & $normalizedKeyValuePairs)
258 $options = $this->getOptions();
259 $namespace = $options->getNamespace();
260 if ($namespace === '') {
261 return wincache_ucache_set($normalizedKeyValuePairs, null, $options->getTtl());
264 $prefix = $namespace . $options->getNamespaceSeparator();
265 $internalKeyValuePairs = array();
266 foreach ($normalizedKeyValuePairs as $normalizedKey => & $value) {
267 $internalKey = $prefix . $normalizedKey;
268 $internalKeyValuePairs[$internalKey] = & $value;
271 $result = wincache_ucache_set($internalKeyValuePairs, null, $options->getTtl());
274 $prefixL = strlen($prefix);
275 foreach ($result as & $key) {
276 $key = substr($key, $prefixL);
285 * @param string $normalizedKey
286 * @param mixed $value
288 * @throws Exception\ExceptionInterface
290 protected function internalAddItem(& $normalizedKey, & $value)
292 $options = $this->getOptions();
293 $namespace = $options->getNamespace();
294 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
295 $internalKey = $prefix . $normalizedKey;
296 $ttl = $options->getTtl();
298 if (!wincache_ucache_add($internalKey, $value, $ttl)) {
299 $type = is_object($value) ?
get_class($value) : gettype($value);
300 throw new Exception\
RuntimeException(
301 "wincache_ucache_add('{$internalKey}', <{$type}>, {$ttl}) failed"
309 * Internal method to add multiple items.
311 * @param array $normalizedKeyValuePairs
312 * @return array Array of not stored keys
313 * @throws Exception\ExceptionInterface
315 protected function internalAddItems(array & $normalizedKeyValuePairs)
317 $options = $this->getOptions();
318 $namespace = $options->getNamespace();
319 if ($namespace === '') {
320 return wincache_ucache_add($normalizedKeyValuePairs, null, $options->getTtl());
323 $prefix = $namespace . $options->getNamespaceSeparator();
324 $internalKeyValuePairs = array();
325 foreach ($normalizedKeyValuePairs as $normalizedKey => $value) {
326 $internalKey = $prefix . $normalizedKey;
327 $internalKeyValuePairs[$internalKey] = $value;
330 $result = wincache_ucache_add($internalKeyValuePairs, null, $options->getTtl());
333 $prefixL = strlen($prefix);
334 foreach ($result as & $key) {
335 $key = substr($key, $prefixL);
342 * Internal method to replace an existing item.
344 * @param string $normalizedKey
345 * @param mixed $value
347 * @throws Exception\ExceptionInterface
349 protected function internalReplaceItem(& $normalizedKey, & $value)
351 $options = $this->getOptions();
352 $namespace = $options->getNamespace();
353 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
354 $internalKey = $prefix . $normalizedKey;
355 if (!wincache_ucache_exists($internalKey)) {
359 $ttl = $options->getTtl();
360 if (!wincache_ucache_set($internalKey, $value, $ttl)) {
361 $type = is_object($value) ?
get_class($value) : gettype($value);
362 throw new Exception\
RuntimeException(
363 "wincache_ucache_set('{$internalKey}', <{$type}>, {$ttl}) failed"
371 * Internal method to remove an item.
373 * @param string $normalizedKey
375 * @throws Exception\ExceptionInterface
377 protected function internalRemoveItem(& $normalizedKey)
379 $options = $this->getOptions();
380 $namespace = $options->getNamespace();
381 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
382 $internalKey = $prefix . $normalizedKey;
383 return wincache_ucache_delete($internalKey);
387 * Internal method to remove multiple items.
389 * @param array $normalizedKeys
390 * @return array Array of not removed keys
391 * @throws Exception\ExceptionInterface
393 protected function internalRemoveItems(array & $normalizedKeys)
395 $options = $this->getOptions();
396 $namespace = $options->getNamespace();
397 if ($namespace === '') {
398 $result = wincache_ucache_delete($normalizedKeys);
399 return ($result === false) ?
$normalizedKeys : $result;
402 $prefix = $namespace . $options->getNamespaceSeparator();
403 $internalKeys = array();
404 foreach ($normalizedKeys as $normalizedKey) {
405 $internalKeys[] = $prefix . $normalizedKey;
408 $result = wincache_ucache_delete($internalKeys);
409 if ($result === false) {
410 return $normalizedKeys;
413 $prefixL = strlen($prefix);
414 foreach ($result as & $key) {
415 $key = substr($key, $prefixL);
423 * Internal method to increment an item.
425 * @param string $normalizedKey
427 * @return int|bool The new value on success, false on failure
428 * @throws Exception\ExceptionInterface
430 protected function internalIncrementItem(& $normalizedKey, & $value)
432 $options = $this->getOptions();
433 $namespace = $options->getNamespace();
434 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
435 $internalKey = $prefix . $normalizedKey;
436 return wincache_ucache_inc($internalKey, (int) $value);
440 * Internal method to decrement an item.
442 * @param string $normalizedKey
444 * @return int|bool The new value on success, false on failure
445 * @throws Exception\ExceptionInterface
447 protected function internalDecrementItem(& $normalizedKey, & $value)
449 $options = $this->getOptions();
450 $namespace = $options->getNamespace();
451 $prefix = ($namespace === '') ?
'' : $namespace . $options->getNamespaceSeparator();
452 $internalKey = $prefix . $normalizedKey;
453 return wincache_ucache_dec($internalKey, (int) $value);
459 * Internal method to get capabilities of this adapter
461 * @return Capabilities
463 protected function internalGetCapabilities()
465 if ($this->capabilities
=== null) {
466 $marker = new stdClass();
467 $capabilities = new Capabilities(
471 'supportedDatatypes' => array(
478 'object' => 'object',
481 'supportedMetadata' => array(
482 'internal_key', 'ttl', 'hits', 'size'
488 'useRequestTime' => false,
489 'expiredRead' => false,
490 'namespaceIsPrefix' => true,
491 'namespaceSeparator' => $this->getOptions()->getNamespaceSeparator(),
495 // update namespace separator on change option
496 $this->getEventManager()->attach('option', function ($event) use ($capabilities, $marker) {
497 $params = $event->getParams();
499 if (isset($params['namespace_separator'])) {
500 $capabilities->setNamespaceSeparator($marker, $params['namespace_separator']);
504 $this->capabilities
= $capabilities;
505 $this->capabilityMarker
= $marker;
508 return $this->capabilities
;
514 * Normalize metadata to work with WinCache
516 * @param array $metadata
519 protected function normalizeMetadata(array & $metadata)
521 $metadata['internal_key'] = $metadata['key_name'];
522 $metadata['hits'] = $metadata['hitcount'];
523 $metadata['ttl'] = $metadata['ttl_seconds'];
524 $metadata['size'] = $metadata['value_size'];
527 $metadata['key_name'],
528 $metadata['hitcount'],
529 $metadata['ttl_seconds'],
530 $metadata['value_size']