3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Cache\Pattern
;
12 use Zend\Cache\Exception
;
13 use Zend\Stdlib\ErrorHandler
;
15 class CallbackCache
extends AbstractPattern
20 * @param PatternOptions $options
21 * @return CallbackCache Provides a fluent interface
22 * @throws Exception\InvalidArgumentException if missing storage option
24 public function setOptions(PatternOptions
$options)
26 parent
::setOptions($options);
28 if (! $options->getStorage()) {
29 throw new Exception\
InvalidArgumentException("Missing option 'storage'");
35 * Call the specified callback or get the result from cache
37 * @param callable $callback A valid callback
38 * @param array $args Callback arguments
39 * @return mixed Result
40 * @throws Exception\RuntimeException if invalid cached data
43 public function call($callback, array $args = [])
45 $options = $this->getOptions();
46 $storage = $options->getStorage();
48 $key = $this->generateCallbackKey($callback, $args);
49 $result = $storage->getItem($key, $success);
51 if (! array_key_exists(0, $result)) {
52 throw new Exception\
RuntimeException("Invalid cached data for key '{$key}'");
55 echo isset($result[1]) ?
$result[1] : '';
59 $cacheOutput = $options->getCacheOutput();
65 // TODO: do not cache on errors using [set|restore]_error_handler
69 $ret = call_user_func_array($callback, $args);
71 $ret = call_user_func($callback);
73 } catch (\Exception
$e) {
81 $data = [$ret, ob_get_flush()];
86 $storage->setItem($key, $data);
92 * function call handler
94 * @param string $function Function name to call
95 * @param array $args Function arguments
97 * @throws Exception\RuntimeException
100 public function __call($function, array $args)
102 return $this->call($function, $args);
106 * Generate a unique key in base of a key representing the callback part
107 * and a key representing the arguments part.
109 * @param callable $callback A valid callback
110 * @param array $args Callback arguments
112 * @throws Exception\RuntimeException
113 * @throws Exception\InvalidArgumentException
115 public function generateKey($callback, array $args = [])
117 return $this->generateCallbackKey($callback, $args);
121 * Generate a unique key in base of a key representing the callback part
122 * and a key representing the arguments part.
124 * @param callable $callback A valid callback
125 * @param array $args Callback arguments
126 * @throws Exception\RuntimeException if callback not serializable
127 * @throws Exception\InvalidArgumentException if invalid callback
130 protected function generateCallbackKey($callback, array $args)
132 if (! is_callable($callback, false, $callbackKey)) {
133 throw new Exception\
InvalidArgumentException('Invalid callback');
136 // functions, methods and classnames are case-insensitive
137 $callbackKey = strtolower($callbackKey);
139 // generate a unique key of object callbacks
140 if (is_object($callback)) {
141 // Closures & __invoke
143 } elseif (isset($callback[0])) {
144 // array($object, 'method')
145 $object = $callback[0];
147 if (isset($object)) {
148 ErrorHandler
::start();
150 $serializedObject = serialize($object);
151 } catch (\Exception
$e) {
152 ErrorHandler
::stop();
153 throw new Exception\
RuntimeException("Can't serialize callback: see previous exception", 0, $e);
155 $error = ErrorHandler
::stop();
157 if (! $serializedObject) {
158 throw new Exception\
RuntimeException(
159 sprintf('Cannot serialize callback%s', ($error ?
': ' . $error->getMessage() : '')),
164 $callbackKey .= $serializedObject;
167 return md5($callbackKey) . $this->generateArgumentsKey($args);
171 * Generate a unique key of the argument part.
174 * @throws Exception\RuntimeException
177 protected function generateArgumentsKey(array $args)
183 ErrorHandler
::start();
185 $serializedArgs = serialize(array_values($args));
186 } catch (\Exception
$e) {
187 ErrorHandler
::stop();
188 throw new Exception\
RuntimeException("Can't serialize arguments: see previous exception", 0, $e);
190 $error = ErrorHandler
::stop();
192 if (! $serializedArgs) {
193 throw new Exception\
RuntimeException(
194 sprintf('Cannot serialize arguments%s', ($error ?
': ' . $error->getMessage() : '')),
200 return md5($serializedArgs);