You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							388 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
	
	
							388 lines
						
					
					
						
							15 KiB
						
					
					
				| <?php | |
| /** | |
|  * @link http://www.yiiframework.com/ | |
|  * @copyright Copyright (c) 2008 Yii Software LLC | |
|  * @license http://www.yiiframework.com/license/ | |
|  */ | |
|  | |
| namespace yii\caching; | |
|  | |
| use Yii; | |
| use yii\base\Component; | |
| use yii\base\InvalidConfigException; | |
| use yii\helpers\StringHelper; | |
|  | |
| /** | |
|  * Cache is the base class for cache classes supporting different cache storage implementation. | |
|  * | |
|  * A data item can be stored in cache by calling [[set()]] and be retrieved back | |
|  * later (in the same or different request) by [[get()]]. In both operations, | |
|  * a key identifying the data item is required. An expiration time and/or a [[Dependency|dependency]] | |
|  * can also be specified when calling [[set()]]. If the data item expires or the dependency | |
|  * changes at the time of calling [[get()]], the cache will return no data. | |
|  * | |
|  * A typical usage pattern of cache is like the following: | |
|  * | |
|  * ~~~ | |
|  * $key = 'demo'; | |
|  * $data = $cache->get($key); | |
|  * if ($data === false) { | |
|  *     // ...generate $data here... | |
|  *     $cache->set($key, $data, $expire, $dependency); | |
|  * } | |
|  * ~~~ | |
|  * | |
|  * Because Cache implements the ArrayAccess interface, it can be used like an array. For example, | |
|  * | |
|  * ~~~ | |
|  * $cache['foo'] = 'some data'; | |
|  * echo $cache['foo']; | |
|  * ~~~ | |
|  * | |
|  * Derived classes should implement the following methods: | |
|  * | |
|  * - [[getValue()]]: retrieve the value with a key (if any) from cache | |
|  * - [[setValue()]]: store the value with a key into cache | |
|  * - [[addValue()]]: store the value only if the cache does not have this key before | |
|  * - [[deleteValue()]]: delete the value with the specified key from cache | |
|  * - [[flushValues()]]: delete all values from cache | |
|  * | |
|  * @author Qiang Xue <qiang.xue@gmail.com> | |
|  * @since 2.0 | |
|  */ | |
| abstract class Cache extends Component implements \ArrayAccess | |
| { | |
| 	/** | |
| 	 * @var string a string prefixed to every cache key so that it is unique. If not set, | |
| 	 * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string | |
| 	 * if you don't want to use key prefix. It is recommended that you explicitly set this property to some | |
| 	 * static value if the cached data needs to be shared among multiple applications. | |
| 	 * | |
| 	 * To ensure interoperability, only use alphanumeric characters should be used. | |
| 	 */ | |
| 	public $keyPrefix; | |
| 	/** | |
| 	 * @var array|boolean the functions used to serialize and unserialize cached data. Defaults to null, meaning | |
| 	 * using the default PHP `serialize()` and `unserialize()` functions. If you want to use some more efficient | |
| 	 * serializer (e.g. [igbinary](http://pecl.php.net/package/igbinary)), you may configure this property with | |
| 	 * a two-element array. The first element specifies the serialization function, and the second the deserialization | |
| 	 * function. If this property is set false, data will be directly sent to and retrieved from the underlying | |
| 	 * cache component without any serialization or deserialization. You should not turn off serialization if | |
| 	 * you are using [[Dependency|cache dependency]], because it relies on data serialization. | |
| 	 */ | |
| 	public $serializer; | |
|  | |
|  | |
| 	/** | |
| 	 * Initializes the application component. | |
| 	 * This method overrides the parent implementation by setting default cache key prefix. | |
| 	 */ | |
| 	public function init() | |
| 	{ | |
| 		parent::init(); | |
| 		if ($this->keyPrefix === null) { | |
| 			$this->keyPrefix = substr(md5(Yii::$app->id), 0, 5); | |
| 		} elseif (!ctype_alnum($this->keyPrefix)) { | |
| 			throw new InvalidConfigException(get_class($this) . '::keyPrefix should only contain alphanumeric characters.'); | |
| 		} | |
| 	} | |
|  | |
| 	/** | |
| 	 * Builds a normalized cache key from a given key. | |
| 	 * | |
| 	 * If the given key is a string containing alphanumeric characters only and no more than 32 characters, | |
| 	 * then the key will be returned back prefixed with [[keyPrefix]]. Otherwise, a normalized key | |
| 	 * is generated by serializing the given key, applying MD5 hashing, and prefixing with [[keyPrefix]]. | |
| 	 * | |
| 	 * @param mixed $key the key to be normalized | |
| 	 * @return string the generated cache key | |
| 	 */ | |
| 	protected function buildKey($key) | |
| 	{ | |
| 		if (is_string($key)) { | |
| 			$key = ctype_alnum($key) && StringHelper::strlen($key) <= 32 ? $key : md5($key); | |
| 		} else { | |
| 			$key = md5(json_encode($key)); | |
| 		} | |
| 		return $this->keyPrefix . $key; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Retrieves a value from cache with a specified key. | |
| 	 * @param mixed $key a key identifying the cached value. This can be a simple string or | |
| 	 * a complex data structure consisting of factors representing the key. | |
| 	 * @return mixed the value stored in cache, false if the value is not in the cache, expired, | |
| 	 * or the dependency associated with the cached data has changed. | |
| 	 */ | |
| 	public function get($key) | |
| 	{ | |
| 		$key = $this->buildKey($key); | |
| 		$value = $this->getValue($key); | |
| 		if ($value === false || $this->serializer === false) { | |
| 			return $value; | |
| 		} elseif ($this->serializer === null) { | |
| 			$value = unserialize($value); | |
| 		} else { | |
| 			$value = call_user_func($this->serializer[1], $value); | |
| 		} | |
| 		if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->getHasChanged($this))) { | |
| 			return $value[0]; | |
| 		} else { | |
| 			return false; | |
| 		} | |
| 	} | |
|  | |
| 	/** | |
| 	 * Checks whether a specified key exists in the cache. | |
| 	 * This can be faster than getting the value from the cache if the data is big. | |
| 	 * In case a cache does not support this feature natively, this method will try to simulate it | |
| 	 * but has no performance improvement over getting it. | |
| 	 * Note that this method does not check whether the dependency associated | |
| 	 * with the cached data, if there is any, has changed. So a call to [[get]] | |
| 	 * may return false while exists returns true. | |
| 	 * @param mixed $key a key identifying the cached value. This can be a simple string or | |
| 	 * a complex data structure consisting of factors representing the key. | |
| 	 * @return boolean true if a value exists in cache, false if the value is not in the cache or expired. | |
| 	 */ | |
| 	public function exists($key) | |
| 	{ | |
| 		$key = $this->buildKey($key); | |
| 		$value = $this->getValue($key); | |
| 		return $value !== false; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Retrieves multiple values from cache with the specified keys. | |
| 	 * Some caches (such as memcache, apc) allow retrieving multiple cached values at the same time, | |
| 	 * which may improve the performance. In case a cache does not support this feature natively, | |
| 	 * this method will try to simulate it. | |
| 	 * @param array $keys list of keys identifying the cached values | |
| 	 * @return array list of cached values corresponding to the specified keys. The array | |
| 	 * is returned in terms of (key, value) pairs. | |
| 	 * If a value is not cached or expired, the corresponding array value will be false. | |
| 	 */ | |
| 	public function mget($keys) | |
| 	{ | |
| 		$keyMap = []; | |
| 		foreach ($keys as $key) { | |
| 			$keyMap[$key] = $this->buildKey($key); | |
| 		} | |
| 		$values = $this->getValues(array_values($keyMap)); | |
| 		$results = []; | |
| 		foreach ($keyMap as $key => $newKey) { | |
| 			$results[$key] = false; | |
| 			if (isset($values[$newKey])) { | |
| 				if ($this->serializer === false) { | |
| 					$results[$key] = $values[$newKey]; | |
| 				} else { | |
| 					$value = $this->serializer === null ? unserialize($values[$newKey]) | |
| 							: call_user_func($this->serializer[1], $values[$newKey]); | |
|  | |
| 					if (is_array($value) && !($value[1] instanceof Dependency && $value[1]->getHasChanged($this))) { | |
| 						$results[$key] = $value[0]; | |
| 					} | |
| 				} | |
| 			} | |
| 		} | |
| 		return $results; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Stores a value identified by a key into cache. | |
| 	 * If the cache already contains such a key, the existing value and | |
| 	 * expiration time will be replaced with the new ones, respectively. | |
| 	 * | |
| 	 * @param mixed $key a key identifying the value to be cached. This can be a simple string or | |
| 	 * a complex data structure consisting of factors representing the key. | |
| 	 * @param mixed $value the value to be cached | |
| 	 * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. | |
| 	 * @param Dependency $dependency dependency of the cached item. If the dependency changes, | |
| 	 * the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. | |
| 	 * This parameter is ignored if [[serializer]] is false. | |
| 	 * @return boolean whether the value is successfully stored into cache | |
| 	 */ | |
| 	public function set($key, $value, $expire = 0, $dependency = null) | |
| 	{ | |
| 		if ($dependency !== null && $this->serializer !== false) { | |
| 			$dependency->evaluateDependency($this); | |
| 		} | |
| 		if ($this->serializer === null) { | |
| 			$value = serialize([$value, $dependency]); | |
| 		} elseif ($this->serializer !== false) { | |
| 			$value = call_user_func($this->serializer[0], [$value, $dependency]); | |
| 		} | |
| 		$key = $this->buildKey($key); | |
| 		return $this->setValue($key, $value, $expire); | |
| 	} | |
|  | |
| 	/** | |
| 	 * Stores multiple items in cache. Each item contains a value identified by a key. | |
| 	 * If the cache already contains such a key, the existing value and | |
| 	 * expiration time will be replaced with the new ones, respectively. | |
| 	 * | |
| 	 * @param array $items the items to be cached, as key-value pairs. Each key can be a simple string or | |
| 	 * a complex data structure consisting of factors representing the key. | |
| 	 * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. | |
| 	 * @return boolean whether the items are successfully stored into cache | |
| 	 */ | |
| 	public function mset($items, $expire = 0) | |
| 	{ | |
| 		return false; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Stores a value identified by a key into cache if the cache does not contain this key. | |
| 	 * Nothing will be done if the cache already contains the key. | |
| 	 * @param mixed $key a key identifying the value to be cached. This can be a simple string or | |
| 	 * a complex data structure consisting of factors representing the key. | |
| 	 * @param mixed $value the value to be cached | |
| 	 * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. | |
| 	 * @param Dependency $dependency dependency of the cached item. If the dependency changes, | |
| 	 * the corresponding value in the cache will be invalidated when it is fetched via [[get()]]. | |
| 	 * This parameter is ignored if [[serializer]] is false. | |
| 	 * @return boolean whether the value is successfully stored into cache | |
| 	 */ | |
| 	public function add($key, $value, $expire = 0, $dependency = null) | |
| 	{ | |
| 		if ($dependency !== null && $this->serializer !== false) { | |
| 			$dependency->evaluateDependency($this); | |
| 		} | |
| 		if ($this->serializer === null) { | |
| 			$value = serialize([$value, $dependency]); | |
| 		} elseif ($this->serializer !== false) { | |
| 			$value = call_user_func($this->serializer[0], [$value, $dependency]); | |
| 		} | |
| 		$key = $this->buildKey($key); | |
| 		return $this->addValue($key, $value, $expire); | |
| 	} | |
|  | |
| 	/** | |
| 	 * Deletes a value with the specified key from cache | |
| 	 * @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or | |
| 	 * a complex data structure consisting of factors representing the key. | |
| 	 * @return boolean if no error happens during deletion | |
| 	 */ | |
| 	public function delete($key) | |
| 	{ | |
| 		$key = $this->buildKey($key); | |
| 		return $this->deleteValue($key); | |
| 	} | |
|  | |
| 	/** | |
| 	 * Deletes all values from cache. | |
| 	 * Be careful of performing this operation if the cache is shared among multiple applications. | |
| 	 * @return boolean whether the flush operation was successful. | |
| 	 */ | |
| 	public function flush() | |
| 	{ | |
| 		return $this->flushValues(); | |
| 	} | |
|  | |
| 	/** | |
| 	 * Retrieves a value from cache with a specified key. | |
| 	 * This method should be implemented by child classes to retrieve the data | |
| 	 * from specific cache storage. | |
| 	 * @param string $key a unique key identifying the cached value | |
| 	 * @return string|boolean the value stored in cache, false if the value is not in the cache or expired. | |
| 	 */ | |
| 	abstract protected function getValue($key); | |
|  | |
| 	/** | |
| 	 * Stores a value identified by a key in cache. | |
| 	 * This method should be implemented by child classes to store the data | |
| 	 * in specific cache storage. | |
| 	 * @param string $key the key identifying the value to be cached | |
| 	 * @param string $value the value to be cached | |
| 	 * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. | |
| 	 * @return boolean true if the value is successfully stored into cache, false otherwise | |
| 	 */ | |
| 	abstract protected function setValue($key, $value, $expire); | |
|  | |
| 	/** | |
| 	 * Stores a value identified by a key into cache if the cache does not contain this key. | |
| 	 * This method should be implemented by child classes to store the data | |
| 	 * in specific cache storage. | |
| 	 * @param string $key the key identifying the value to be cached | |
| 	 * @param string $value the value to be cached | |
| 	 * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. | |
| 	 * @return boolean true if the value is successfully stored into cache, false otherwise | |
| 	 */ | |
| 	abstract protected function addValue($key, $value, $expire); | |
|  | |
| 	/** | |
| 	 * Deletes a value with the specified key from cache | |
| 	 * This method should be implemented by child classes to delete the data from actual cache storage. | |
| 	 * @param string $key the key of the value to be deleted | |
| 	 * @return boolean if no error happens during deletion | |
| 	 */ | |
| 	abstract protected function deleteValue($key); | |
|  | |
| 	/** | |
| 	 * Deletes all values from cache. | |
| 	 * Child classes may implement this method to realize the flush operation. | |
| 	 * @return boolean whether the flush operation was successful. | |
| 	 */ | |
| 	abstract protected function flushValues(); | |
|  | |
| 	/** | |
| 	 * Retrieves multiple values from cache with the specified keys. | |
| 	 * The default implementation calls [[getValue()]] multiple times to retrieve | |
| 	 * the cached values one by one. If the underlying cache storage supports multiget, | |
| 	 * this method should be overridden to exploit that feature. | |
| 	 * @param array $keys a list of keys identifying the cached values | |
| 	 * @return array a list of cached values indexed by the keys | |
| 	 */ | |
| 	protected function getValues($keys) | |
| 	{ | |
| 		$results = []; | |
| 		foreach ($keys as $key) { | |
| 			$results[$key] = $this->getValue($key); | |
| 		} | |
| 		return $results; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Returns whether there is a cache entry with a specified key. | |
| 	 * This method is required by the interface ArrayAccess. | |
| 	 * @param string $key a key identifying the cached value | |
| 	 * @return boolean | |
| 	 */ | |
| 	public function offsetExists($key) | |
| 	{ | |
| 		return $this->get($key) !== false; | |
| 	} | |
|  | |
| 	/** | |
| 	 * Retrieves the value from cache with a specified key. | |
| 	 * This method is required by the interface ArrayAccess. | |
| 	 * @param string $key a key identifying the cached value | |
| 	 * @return mixed the value stored in cache, false if the value is not in the cache or expired. | |
| 	 */ | |
| 	public function offsetGet($key) | |
| 	{ | |
| 		return $this->get($key); | |
| 	} | |
|  | |
| 	/** | |
| 	 * Stores the value identified by a key into cache. | |
| 	 * If the cache already contains such a key, the existing value will be | |
| 	 * replaced with the new ones. To add expiration and dependencies, use the [[set()]] method. | |
| 	 * This method is required by the interface ArrayAccess. | |
| 	 * @param string $key the key identifying the value to be cached | |
| 	 * @param mixed $value the value to be cached | |
| 	 */ | |
| 	public function offsetSet($key, $value) | |
| 	{ | |
| 		$this->set($key, $value); | |
| 	} | |
|  | |
| 	/** | |
| 	 * Deletes the value with the specified key from cache | |
| 	 * This method is required by the interface ArrayAccess. | |
| 	 * @param string $key the key of the value to be deleted | |
| 	 */ | |
| 	public function offsetUnset($key) | |
| 	{ | |
| 		$this->delete($key); | |
| 	} | |
| }
 | |
| 
 |