Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
asset_cache.inc
1 <?php
18 // If 1, getForgottenItemsReport() will include the callers of the cache
19 // which forgot to release their reference to the assets
20 define('SQ_ASSET_CACHE_DEBUG', 0);
21 
43 {
44 
51  var $_items = Array();
52 
60  var $_items_released = Array();
61 
73  var $_size_rules;
74 
75 
82  function Asset_Cache()
83  {
84  $this->setSizeRules();
85 
86  }//end constructor
87 
88 
100  function setSizeRules($size=-1, $all_items=false)
101  {
102  $this->_size_rules['max'] = $size;
103  $this->_size_rules['all_items'] = $all_items;
104 
105  }//end setSizeRules()
106 
107 
119  function add($item, $itemid=-1)
120  {
121  if ($itemid == -1) {
122  // no valid id
123  if (!isset($item) || !isset($item->id)) {
124  return false;
125  }
126  $itemid = $item->id;
127  }
128 
129  // already in the cache
130  if ($this->get($itemid)) return false;
131 
132  $this->_items[$itemid] = Array('item' => $item, 'reference_count' => 1);
133 
134  if (SQ_ASSET_CACHE_DEBUG) {
135  $this->_trackCaller($itemid, 1);
136  }
137 
138  return true;
139 
140  }//end add()
141 
142 
152  function get($itemid)
153  {
154  $ret = null;
155 
156  if (isset($this->_items[$itemid])) {
157  $item_info = &$this->_items[$itemid];
158 
159  $ret = &$item_info['item'];
160 
161  if ($item_info['reference_count'] == 0) {
162  unset($this->_items_released[$itemid]);
163  }
164 
165  $item_info['reference_count']++;
166 
167  if (SQ_ASSET_CACHE_DEBUG) {
168  $this->_trackCaller($itemid, 1);
169  }
170  }
171 
172  return $ret;
173 
174  }//end get()
175 
176 
187  function release($itemid)
188  {
189  if (!isset($this->_items[$itemid])) return false;
190 
191  $item_info = &$this->_items[$itemid];
192 
193  if ($item_info['reference_count'] <= 0) return false;
194 
195  $item_info['reference_count']--;
196 
197  if (SQ_ASSET_CACHE_DEBUG) {
198  $this->_trackCaller($itemid, -1);
199  }
200 
201  if ($item_info['reference_count'] == 0) {
202  $this->_items_released[$itemid] = $itemid;
203  $this->_applySizeRules();
204  }
205 
206  return true;
207 
208  }//end release()
209 
210 
218  function _applySizeRules()
219  {
220  // size -1 disable automatic remove
221  if ($this->_size_rules['max'] == -1) return;
222 
223  if (count($this->_items_released) && $this->getSize(true)) {
224  $current_size = $this->getSize(!$this->_size_rules['all_items']);
225 
226  if ($current_size > $this->_size_rules['max']) {
227  // rules not respected, remove the oldest item
228  reset($this->_items_released);
229  $this->remove(current($this->_items_released));
230  }
231  }
232 
233  }//end _applySizeRules()
234 
235 
248  function remove($itemid, $force=false)
249  {
250  if (!$force && ($this->_items[$itemid]['reference_count'] != 0)) {
251  return false;
252  }
253 
254  unset($this->_items[$itemid]);
255  unset($this->_items_released[$itemid]);
256 
257  return true;
258 
259  }//end remove()
260 
261 
268  function removeAll()
269  {
270  $itemsid = array_keys($this->_items_released);
271  foreach ($itemsid as $itemid) {
272  $this->remove($itemid);
273  }
274 
275  }//end removeAll()
276 
277 
287  function getSize($released=false)
288  {
289  return $released ? count($this->_items_released) : count($this->_items);
290 
291  }//end getSize()
292 
293 
302  {
303  $ret = '';
304 
305  ob_start();
306 
307  echo "Asset Cache report:\n";
308 
309  $item_count = 0;
310  foreach ($this->_items as $itemid => $item_info) {
311  if ($item_info['reference_count'] > 0) {
312  echo 'Asset #'.$itemid.' ('.get_class($item_info['item']).') RC='.$item_info['reference_count']."\n";
313  if (isset($item_info['callers'])) {
314  print_r ($item_info['callers']);
315  }
316  $item_count++;
317  }
318  }
319  echo $item_count." items \n";
320 
321  $ret = ob_get_clean();
322 
323  return $ret;
324 
325  }//end getForgottenItemsReport()
326 
327 
338  function _trackCaller($itemid, $rc_diff)
339  {
340  // 1. get class name
341  $bt = debug_backtrace();
342 
343  $caller = '???';
344  $excluded_classes = Array('asset_manager', 'asset', strtolower(__CLASS__));
345  for ($caller_idx = 0; $caller_idx < count($bt); $caller_idx++) {
346  $class = (isset($bt[$caller_idx]['class'])) ? $bt[$caller_idx]['class'] : '';
347  if (!in_array(strtolower($class), $excluded_classes)) {
348  break;
349  }
350  }
351  if ($caller_idx < count($bt)) {
352  $caller = (isset($bt[$caller_idx]['class'])) ? $bt[$caller_idx]['class'] : '';
353  $caller .= ':'.$bt[$caller_idx]['file'];
354  }
355 
356  // 2. add info to the cache
357  if (!isset($this->_items[$itemid]['callers'])) {
358  $this->_items[$itemid]['callers'] = Array();
359  }
360  if (!isset($this->_items[$itemid]['callers'][$caller])) {
361  $this->_items[$itemid]['callers'][$caller] = 0;
362  }
363  $this->_items[$itemid]['callers'][$caller] += $rc_diff;
364 
365  }//end _trackCaller()
366 
367 
374  function getAssetKeys()
375  {
376  return array_keys($this->_items);
377 
378  }//end getAssetKeys()
379 
380 
381 }//end class
382 
383 ?>