Source of file Memory.php
Size: 20,107 Bytes - Last Modified: 2014-03-12T23:21:18+01:00
/home/theseer/Downloads/ZendFramework-2.3.0/library/Zend/Cache/Storage/Adapter/Memory.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 | <?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\Cache\Storage\Adapter; use stdClass; use Zend\Cache\Exception; use Zend\Cache\Storage\AvailableSpaceCapableInterface; use Zend\Cache\Storage\Capabilities; use Zend\Cache\Storage\ClearByNamespaceInterface; use Zend\Cache\Storage\ClearByPrefixInterface; use Zend\Cache\Storage\ClearExpiredInterface; use Zend\Cache\Storage\FlushableInterface; use Zend\Cache\Storage\IterableInterface; use Zend\Cache\Storage\TaggableInterface; use Zend\Cache\Storage\TotalSpaceCapableInterface; class Memory extends AbstractAdapter implements AvailableSpaceCapableInterface, ClearByPrefixInterface, ClearByNamespaceInterface, ClearExpiredInterface, FlushableInterface, IterableInterface, TaggableInterface, TotalSpaceCapableInterface { /** * Data Array * * Format: * array( * <NAMESPACE> => array( * <KEY> => array( * 0 => <VALUE> * 1 => <MICROTIME> * ['tags' => <TAGS>] * ) * ) * ) * * @var array */ protected $data = array(); /** * Set options. * * @param array|\Traversable|MemoryOptions $options * @return Memory * @see getOptions() */ public function setOptions($options) { if (!$options instanceof MemoryOptions) { $options = new MemoryOptions($options); } return parent::setOptions($options); } /** * Get options. * * @return MemoryOptions * @see setOptions() */ public function getOptions() { if (!$this->options) { $this->setOptions(new MemoryOptions()); } return $this->options; } /* TotalSpaceCapableInterface */ /** * Get total space in bytes * * @return int|float */ public function getTotalSpace() { return $this->getOptions()->getMemoryLimit(); } /* AvailableSpaceCapableInterface */ /** * Get available space in bytes * * @return int|float */ public function getAvailableSpace() { $total = $this->getOptions()->getMemoryLimit(); $avail = $total - (float) memory_get_usage(true); return ($avail > 0) ? $avail : 0; } /* IterableInterface */ /** * Get the storage iterator * * @return KeyListIterator */ public function getIterator() { $ns = $this->getOptions()->getNamespace(); $keys = array(); if (isset($this->data[$ns])) { foreach ($this->data[$ns] as $key => & $tmp) { if ($this->internalHasItem($key)) { $keys[] = $key; } } } return new KeyListIterator($this, $keys); } /* FlushableInterface */ /** * Flush the whole storage * * @return bool */ public function flush() { $this->data = array(); return true; } /* ClearExpiredInterface */ /** * Remove expired items * * @return bool */ public function clearExpired() { $ttl = $this->getOptions()->getTtl(); if ($ttl <= 0) { return true; } $ns = $this->getOptions()->getNamespace(); if (!isset($this->data[$ns])) { return true; } $data = & $this->data[$ns]; foreach ($data as $key => & $item) { if (microtime(true) >= $data[$key][1] + $ttl) { unset($data[$key]); } } return true; } /* ClearByNamespaceInterface */ public function clearByNamespace($namespace) { $namespace = (string) $namespace; if ($namespace === '') { throw new Exception\InvalidArgumentException('No namespace given'); } unset($this->data[$namespace]); return true; } /* ClearByPrefixInterface */ /** * Remove items matching given prefix * * @param string $prefix * @return bool */ public function clearByPrefix($prefix) { $prefix = (string) $prefix; if ($prefix === '') { throw new Exception\InvalidArgumentException('No prefix given'); } $ns = $this->getOptions()->getNamespace(); if (!isset($this->data[$ns])) { return true; } $prefixL = strlen($prefix); $data = & $this->data[$ns]; foreach ($data as $key => & $item) { if (substr($key, 0, $prefixL) === $prefix) { unset($data[$key]); } } return true; } /* TaggableInterface */ /** * Set tags to an item by given key. * An empty array will remove all tags. * * @param string $key * @param string[] $tags * @return bool */ public function setTags($key, array $tags) { $ns = $this->getOptions()->getNamespace(); if (!$this->data[$ns]) { return false; } $data = & $this->data[$ns]; if (isset($data[$key])) { $data[$key]['tags'] = $tags; return true; } return false; } /** * Get tags of an item by given key * * @param string $key * @return string[]|FALSE */ public function getTags($key) { $ns = $this->getOptions()->getNamespace(); if (!$this->data[$ns]) { return false; } $data = & $this->data[$ns]; if (!isset($data[$key])) { return false; } return isset($data[$key]['tags']) ? $data[$key]['tags'] : array(); } /** * Remove items matching given tags. * * If $disjunction only one of the given tags must match * else all given tags must match. * * @param string[] $tags * @param bool $disjunction * @return bool */ public function clearByTags(array $tags, $disjunction = false) { $ns = $this->getOptions()->getNamespace(); if (!$this->data[$ns]) { return true; } $tagCount = count($tags); $data = & $this->data[$ns]; foreach ($data as $key => & $item) { if (isset($item['tags'])) { $diff = array_diff($tags, $item['tags']); if (($disjunction && count($diff) < $tagCount) || (!$disjunction && !$diff)) { unset($data[$key]); } } } return true; } /* reading */ /** * Internal method to get an item. * * @param string $normalizedKey * @param bool $success * @param mixed $casToken * @return mixed Data on success, null on failure * @throws Exception\ExceptionInterface */ protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null) { $options = $this->getOptions(); $ns = $options->getNamespace(); $success = isset($this->data[$ns][$normalizedKey]); if ($success) { $data = & $this->data[$ns][$normalizedKey]; $ttl = $options->getTtl(); if ($ttl && microtime(true) >= ($data[1] + $ttl)) { $success = false; } } if (!$success) { return null; } $casToken = $data[0]; return $data[0]; } /** * Internal method to get multiple items. * * @param array $normalizedKeys * @return array Associative array of keys and values * @throws Exception\ExceptionInterface */ protected function internalGetItems(array & $normalizedKeys) { $options = $this->getOptions(); $ns = $options->getNamespace(); if (!isset($this->data[$ns])) { return array(); } $data = & $this->data[$ns]; $ttl = $options->getTtl(); $now = microtime(true); $result = array(); foreach ($normalizedKeys as $normalizedKey) { if (isset($data[$normalizedKey])) { if (!$ttl || $now < ($data[$normalizedKey][1] + $ttl)) { $result[$normalizedKey] = $data[$normalizedKey][0]; } } } return $result; } /** * Internal method to test if an item exists. * * @param string $normalizedKey * @return bool */ protected function internalHasItem(& $normalizedKey) { $options = $this->getOptions(); $ns = $options->getNamespace(); if (!isset($this->data[$ns][$normalizedKey])) { return false; } // check if expired $ttl = $options->getTtl(); if ($ttl && microtime(true) >= ($this->data[$ns][$normalizedKey][1] + $ttl)) { return false; } return true; } /** * Internal method to test multiple items. * * @param array $normalizedKeys * @return array Array of found keys */ protected function internalHasItems(array & $normalizedKeys) { $options = $this->getOptions(); $ns = $options->getNamespace(); if (!isset($this->data[$ns])) { return array(); } $data = & $this->data[$ns]; $ttl = $options->getTtl(); $now = microtime(true); $result = array(); foreach ($normalizedKeys as $normalizedKey) { if (isset($data[$normalizedKey])) { if (!$ttl || $now < ($data[$normalizedKey][1] + $ttl)) { $result[] = $normalizedKey; } } } return $result; } /** * Get metadata of an item. * * @param string $normalizedKey * @return array|bool Metadata on success, false on failure * @throws Exception\ExceptionInterface * * @triggers getMetadata.pre(PreEvent) * @triggers getMetadata.post(PostEvent) * @triggers getMetadata.exception(ExceptionEvent) */ protected function internalGetMetadata(& $normalizedKey) { if (!$this->internalHasItem($normalizedKey)) { return false; } $ns = $this->getOptions()->getNamespace(); return array( 'mtime' => $this->data[$ns][$normalizedKey][1], ); } /* writing */ /** * Internal method to store an item. * * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface */ protected function internalSetItem(& $normalizedKey, & $value) { $options = $this->getOptions(); if (!$this->hasAvailableSpace()) { $memoryLimit = $options->getMemoryLimit(); throw new Exception\OutOfSpaceException( "Memory usage exceeds limit ({$memoryLimit})." ); } $ns = $options->getNamespace(); $this->data[$ns][$normalizedKey] = array($value, microtime(true)); return true; } /** * Internal method to store multiple items. * * @param array $normalizedKeyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface */ protected function internalSetItems(array & $normalizedKeyValuePairs) { $options = $this->getOptions(); if (!$this->hasAvailableSpace()) { $memoryLimit = $options->getMemoryLimit(); throw new Exception\OutOfSpaceException( "Memory usage exceeds limit ({$memoryLimit})." ); } $ns = $options->getNamespace(); if (!isset($this->data[$ns])) { $this->data[$ns] = array(); } $data = & $this->data[$ns]; $now = microtime(true); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { $data[$normalizedKey] = array($value, $now); } return array(); } /** * Add an item. * * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface */ protected function internalAddItem(& $normalizedKey, & $value) { $options = $this->getOptions(); if (!$this->hasAvailableSpace()) { $memoryLimit = $options->getMemoryLimit(); throw new Exception\OutOfSpaceException( "Memory usage exceeds limit ({$memoryLimit})." ); } $ns = $options->getNamespace(); if (isset($this->data[$ns][$normalizedKey])) { return false; } $this->data[$ns][$normalizedKey] = array($value, microtime(true)); return true; } /** * Internal method to add multiple items. * * @param array $normalizedKeyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface */ protected function internalAddItems(array & $normalizedKeyValuePairs) { $options = $this->getOptions(); if (!$this->hasAvailableSpace()) { $memoryLimit = $options->getMemoryLimit(); throw new Exception\OutOfSpaceException( "Memory usage exceeds limit ({$memoryLimit})." ); } $ns = $options->getNamespace(); if (!isset($this->data[$ns])) { $this->data[$ns] = array(); } $result = array(); $data = & $this->data[$ns]; $now = microtime(true); foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { if (isset($data[$normalizedKey])) { $result[] = $normalizedKey; } else { $data[$normalizedKey] = array($value, $now); } } return $result; } /** * Internal method to replace an existing item. * * @param string $normalizedKey * @param mixed $value * @return bool * @throws Exception\ExceptionInterface */ protected function internalReplaceItem(& $normalizedKey, & $value) { $ns = $this->getOptions()->getNamespace(); if (!isset($this->data[$ns][$normalizedKey])) { return false; } $this->data[$ns][$normalizedKey] = array($value, microtime(true)); return true; } /** * Internal method to replace multiple existing items. * * @param array $normalizedKeyValuePairs * @return array Array of not stored keys * @throws Exception\ExceptionInterface */ protected function internalReplaceItems(array & $normalizedKeyValuePairs) { $ns = $this->getOptions()->getNamespace(); if (!isset($this->data[$ns])) { return array_keys($normalizedKeyValuePairs); } $result = array(); $data = & $this->data[$ns]; foreach ($normalizedKeyValuePairs as $normalizedKey => $value) { if (!isset($data[$normalizedKey])) { $result[] = $normalizedKey; } else { $data[$normalizedKey] = array($value, microtime(true)); } } return $result; } /** * Internal method to reset lifetime of an item * * @param string $normalizedKey * @return bool * @throws Exception\ExceptionInterface */ protected function internalTouchItem(& $normalizedKey) { $ns = $this->getOptions()->getNamespace(); if (!isset($this->data[$ns][$normalizedKey])) { return false; } $this->data[$ns][$normalizedKey][1] = microtime(true); return true; } /** * Internal method to remove an item. * * @param string $normalizedKey * @return bool * @throws Exception\ExceptionInterface */ protected function internalRemoveItem(& $normalizedKey) { $ns = $this->getOptions()->getNamespace(); if (!isset($this->data[$ns][$normalizedKey])) { return false; } unset($this->data[$ns][$normalizedKey]); // remove empty namespace if (!$this->data[$ns]) { unset($this->data[$ns]); } return true; } /** * Internal method to increment an item. * * @param string $normalizedKey * @param int $value * @return int|bool The new value on success, false on failure * @throws Exception\ExceptionInterface */ protected function internalIncrementItem(& $normalizedKey, & $value) { $ns = $this->getOptions()->getNamespace(); $data = & $this->data[$ns]; if (isset($data[$normalizedKey])) { $data[$normalizedKey][0]+= $value; $data[$normalizedKey][1] = microtime(true); $newValue = $data[$normalizedKey][0]; } else { // initial value $newValue = $value; $data[$normalizedKey] = array($newValue, microtime(true)); } return $newValue; } /** * Internal method to decrement an item. * * @param string $normalizedKey * @param int $value * @return int|bool The new value on success, false on failure * @throws Exception\ExceptionInterface */ protected function internalDecrementItem(& $normalizedKey, & $value) { $ns = $this->getOptions()->getNamespace(); $data = & $this->data[$ns]; if (isset($data[$normalizedKey])) { $data[$normalizedKey][0]-= $value; $data[$normalizedKey][1] = microtime(true); $newValue = $data[$normalizedKey][0]; } else { // initial value $newValue = -$value; $data[$normalizedKey] = array($newValue, microtime(true)); } return $newValue; } /* status */ /** * Internal method to get capabilities of this adapter * * @return Capabilities */ protected function internalGetCapabilities() { if ($this->capabilities === null) { $this->capabilityMarker = new stdClass(); $this->capabilities = new Capabilities( $this, $this->capabilityMarker, array( 'supportedDatatypes' => array( 'NULL' => true, 'boolean' => true, 'integer' => true, 'double' => true, 'string' => true, 'array' => true, 'object' => true, 'resource' => true, ), 'supportedMetadata' => array('mtime'), 'minTtl' => 1, 'maxTtl' => PHP_INT_MAX, 'staticTtl' => false, 'ttlPrecision' => 0.05, 'expiredRead' => true, 'maxKeyLength' => 0, 'namespaceIsPrefix' => false, 'namespaceSeparator' => '', ) ); } return $this->capabilities; } /* internal */ /** * Has space available to store items? * * @return bool */ protected function hasAvailableSpace() { $total = $this->getOptions()->getMemoryLimit(); // check memory limit disabled if ($total <= 0) { return true; } $free = $total - (float) memory_get_usage(true); return ($free > 0); } } |