1: <?php
2: /**
3: * Decorator for Horde_Autoloader that implements caching of class-file-maps.
4: *
5: * @author Jan Schneider <jan@horde.org>
6: * @category Horde
7: * @package Autoloader_Cache
8: */
9: require_once 'Horde/Autoloader/Default.php';
10:
11: class Horde_Autoloader_Cache extends Horde_Autoloader_Default
12: {
13: /* Cache types. */
14: const APC = 1;
15: const XCACHE = 2;
16: const EACCELERATOR = 3;
17: const TEMPFILE = 4;
18:
19: /**
20: * Map of all classes already looked up.
21: *
22: * @var array
23: */
24: protected $_cache = array();
25:
26: /**
27: * THe cache type.
28: *
29: * @var array
30: */
31: protected $_cachetype;
32:
33: /**
34: * Cache key name.
35: *
36: * @var string
37: */
38: protected $_cachekey = 'horde_autoloader_cache';
39:
40: /**
41: * Has the cache changed since the last save?
42: *
43: * @var boolean
44: */
45: protected $_changed = false;
46:
47: /**
48: * Cached value of the temporary directory.
49: *
50: * @var string
51: */
52: protected $_tempdir;
53:
54: /**
55: * Constructor.
56: *
57: * Tries all supported cache backends and tries to retrieved the cached
58: * class map.
59: */
60: public function __construct()
61: {
62: parent::__construct();
63:
64: if (isset($_SERVER['SERVER_NAME'])) {
65: $this->_cachekey .= '|' . $_SERVER['SERVER_NAME'];
66: }
67: $this->_cachekey .= '|' . __FILE__;
68:
69: if (extension_loaded('apc')) {
70: $this->_cache = apc_fetch($this->_cachekey);
71: $this->_cachetype = self::APC;
72: } elseif (extension_loaded('xcache')) {
73: $this->_cache = xcache_get($this->_cachekey);
74: $this->_cachetype = self::XCACHE;
75: } elseif (extension_loaded('eaccelerator')) {
76: $this->_cache = eaccelerator_get($this->_cachekey);
77: $this->_cachetype = self::EACCELERATOR;
78: } elseif (($this->_tempdir = sys_get_temp_dir()) &&
79: is_readable($this->_tempdir)) {
80: $this->_cachekey = hash('md5', $this->_cachekey);
81: if (($data = file_get_contents($this->_tempdir . '/' . $this->_cachekey)) !== false) {
82: $this->_cache = @json_decode($data, true);
83: }
84: $this->_cachetype = self::TEMPFILE;
85: }
86: }
87:
88: /**
89: * Destructor.
90: *
91: * Tries all supported cache backends and tries to save the class map to
92: * the cache.
93: */
94: public function __destruct()
95: {
96: if (!$this->_changed) {
97: return;
98: }
99:
100: switch ($this->_cachetype) {
101: case self::APC:
102: apc_store($this->_cachekey, $this->_cache);
103: break;
104:
105: case self::XCACHE:
106: xcache_set($this->_cachekey, $this->_cache);
107: break;
108:
109: case self::EACCELERATOR:
110: eaccelerator_put($this->_cachekey, $this->_cache);
111: break;
112:
113: case self::TEMPFILE:
114: file_put_contents($this->_tempdir . '/' . $this->_cachekey, json_encode($this->_cache));
115: break;
116: }
117: }
118:
119: /**
120: * Search registered mappers in LIFO order.
121: *
122: * @param string $className TODO.
123: *
124: * @return string TODO
125: */
126: public function mapToPath($className)
127: {
128: if (!$this->_cache) {
129: $this->_cache = array();
130: }
131: if (!array_key_exists($className, $this->_cache)) {
132: $this->_cache[$className] = parent::mapToPath($className);
133: $this->_changed = true;
134: }
135:
136: return $this->_cache[$className];
137: }
138:
139: /**
140: * Prunes the autoloader cache.
141: *
142: * @return boolean True if pruning succeeded.
143: */
144: public function prune()
145: {
146: if (extension_loaded('apc')) {
147: return apc_delete($this->_cachekey);
148: }
149: if (extension_loaded('xcache')) {
150: return xcache_unset($this->_cachekey);
151: }
152: if (extension_loaded('eaccelerator')) {
153: /* Undocumented, unknown return value. */
154: eaccelerator_rm($this->_cachekey);
155: return true;
156: }
157: if ($this->_tempdir) {
158: return unlink($this->_tempdir . '/' . $this->_cachekey);
159: }
160: return false;
161: }
162: }
163:
164: spl_autoload_unregister(array($__autoloader, 'loadClass'));
165: $__autoloader = new Horde_Autoloader_Cache();
166: $__autoloader->registerAutoloader();
167: