1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
<?php
/** proxy
* implements the proxy design pattern
*
* uses: Registry::cache
*
* algorithm:
* - 1: proxy gets (Class::method, Arguments) and calculates a unique key
* - 2: if a valid Cache for the triplete's key exists, it is served immediately
* - 3: otherwise calls Class::Method(Arguments), caches then serves response
*
* @param $class_method (array): a 2 (string) items array in the form
* : [ 'fully\qualifies\ClassName' , 'methodName' ]
* : Using the ClassName::class notation is strongly recommended.
* @param $args: array of arguments (passed to the Class::Method())
* @param $ttl: time (in sec) where the data will remain valid (not expired)
* @param $options: bitwise flags*
* ---
* @return $data (mixed)
*
* (*) option flags
* all option flags represend non default behaviour of proxy
* ---
* PROXY_CACHE_ERRORS : cache value even if callback returns error
* PROXY_IGNORE_CACHE : ignore if cache exist; get result from callback
* PROXY_DO_NOT_CACHE : do not cache the result (even if from callback)
*/
function proxy(array $callable, array $args, int $ttl, int $options=0)
{
// resolve option flags
$cache_errors = ($options&PROXY_CACHE_ERRORS) ? true : false;
$ignore_cache = ($options&PROXY_IGNORE_CACHE) ? true : false;
$do_not_cache = ($options&PROXY_DO_NOT_CACHE) ? true : false;
// we're gonna use cache;
$cache = Registry::use('cache');
// check validity of callable argument
// -------------------------------------------------------------------------
if ((!is_callable($callable)) || (!is_array($callable))) {
throw new Exception(
'Proxy\'s first parameter has to be a callable array [fully\\qualified\\ClassName, method], passed:'.print_r($callable, true)
);
}
// create a unique key
// -------------------------------------------------------------------------
list($class, $method) = $callable;
$key = sha1(
$class .':'. $method .':'. json_encode(
$args, JSON_UNESCAPED_LINE_TERMINATORS|JSON_UNESCAPED_UNICODE
)
);
// search cache if data for this key exist
// -------------------------------------------------------------------------
if (!$ignore_cache) {
$data = $cache->get($key);
} else { $data = false; } // ignore cache? pass false
if ($data !== false) { // if exists, serve cached data
// if cashed data exist
// ---------------------------------------------------------------------
# if (!PRODUCTION) Benchmark::add_spot('proxy-cached');
if ($data == '_ERROR_') return false; // previous cached error
else return $data; // previous cache ()
} else { // else (not exist)...
// no data on cache -> get data from Class::method( arguments )
// ---------------------------------------------------------------------
$data = call_user_func_array($callable, $args);
// handle newly created data
// ---------------------------------------------------------------------
// if faulty data, return false
if ($data == false) {
if ($cache_errors && !$do_not_cache) { // cache the error
$cache->set($key, '_ERROR_', $ttl);
}
# if (!PRODUCTION) Benchmark::add_spot('proxy-new-error');
return false;
}
// store to cache
if (!$do_not_cache) {
$cache->set($key, $data, $ttl);
}
# if (!PRODUCTION) Benchmark::add_spot('proxy-new');
return $data; // serve data
}
}
|