Skip to content

Commit 234865d

Browse files
committed
Add APCu support
Support for the APCu extension (through sfAPCuCache) as an alternative to APC, which no longer works with recent versions of PHP.
1 parent fa379ab commit 234865d

File tree

6 files changed

+225
-12
lines changed

6 files changed

+225
-12
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ jobs:
3939
uses: shivammathur/setup-php@v2
4040
with:
4141
php-version: "${{ matrix.php-version }}"
42+
extensions: apcu
43+
ini-values: apc.enable_cli=1
4244

4345
- name: Get composer cache directory
4446
id: composer-cache

data/bin/check_configuration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function get_ini_path()
7777
check(function_exists('posix_isatty'), 'The posix_isatty() is available', 'Install and enable the php_posix extension (used to colorized the CLI output)', false);
7878

7979
$accelerator =
80-
(function_exists('apc_store') && ini_get('apc.enabled'))
80+
((function_exists('apc_store') || function_exists('apcu_store')) && ini_get('apc.enabled'))
8181
|| function_exists('eaccelerator_put') && ini_get('eaccelerator.enable')
8282
|| function_exists('xcache_set');
8383
check($accelerator, 'A PHP accelerator is installed', 'Install a PHP accelerator like APC (highly recommended)', false);

docker-compose.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ services:
9494
args:
9595
PHP_TAG: '7.0-cli-jessie'
9696
MEMCACHE_VERSION: '4.0.5.2'
97-
APCU_VERSION: ''
97+
APCU_VERSION: '5.1.23'
9898

9999
php71:
100100
<<: *services_php54
@@ -103,7 +103,7 @@ services:
103103
args:
104104
PHP_TAG: '7.1-cli-jessie'
105105
MEMCACHE_VERSION: '4.0.5.2'
106-
APCU_VERSION: ''
106+
APCU_VERSION: '5.1.23'
107107

108108

109109
php72:
@@ -113,7 +113,7 @@ services:
113113
args:
114114
PHP_VERSION: '7.2'
115115
MEMCACHE_VERSION: '4.0.5.2'
116-
APCU_VERSION: ''
116+
APCU_VERSION: '5.1.23'
117117

118118

119119
php73:
@@ -123,7 +123,7 @@ services:
123123
args:
124124
PHP_VERSION: '7.3'
125125
MEMCACHE_VERSION: '4.0.5.2'
126-
APCU_VERSION: ''
126+
APCU_VERSION: '5.1.23'
127127

128128

129129
php74:
@@ -133,7 +133,7 @@ services:
133133
args:
134134
PHP_VERSION: '7.4'
135135
MEMCACHE_VERSION: '4.0.5.2'
136-
APCU_VERSION: ''
136+
APCU_VERSION: '5.1.23'
137137

138138

139139
php80:
@@ -143,7 +143,7 @@ services:
143143
args:
144144
PHP_VERSION: '8.0'
145145
MEMCACHE_VERSION: '8.0'
146-
APCU_VERSION: ''
146+
APCU_VERSION: '5.1.23'
147147

148148

149149
php81:
@@ -153,7 +153,7 @@ services:
153153
args:
154154
PHP_VERSION: '8.1'
155155
MEMCACHE_VERSION: '8.0'
156-
APCU_VERSION: ''
156+
APCU_VERSION: '5.1.23'
157157

158158
php82:
159159
<<: *services_php54
@@ -162,7 +162,7 @@ services:
162162
args:
163163
PHP_VERSION: '8.2'
164164
MEMCACHE_VERSION: '8.0'
165-
APCU_VERSION: ''
165+
APCU_VERSION: '5.1.23'
166166

167167
php83:
168168
<<: *services_php54
@@ -171,7 +171,7 @@ services:
171171
args:
172172
PHP_VERSION: '8.3'
173173
MEMCACHE_VERSION: '8.0'
174-
APCU_VERSION: ''
174+
APCU_VERSION: '5.1.23'
175175

176176

177177
db:

lib/autoload/sfCoreAutoload.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class sfCoreAutoload
4444
'sfcoreautoload' => 'autoload/sfCoreAutoload.class.php',
4545
'sfsimpleautoload' => 'autoload/sfSimpleAutoload.class.php',
4646
'sfapccache' => 'cache/sfAPCCache.class.php',
47+
'sfapcucache' => 'cache/sfAPCuCache.class.php',
4748
'sfcache' => 'cache/sfCache.class.php',
4849
'sfeacceleratorcache' => 'cache/sfEAcceleratorCache.class.php',
4950
'sffilecache' => 'cache/sfFileCache.class.php',

lib/cache/sfAPCuCache.class.php

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the symfony package.
5+
* (c) 2004-2006 Fabien Potencier <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
/**
12+
* Cache class that stores cached content in APCu.
13+
*
14+
* @author Fabien Potencier <[email protected]>
15+
* @author Paulo M
16+
*
17+
* @version SVN: $Id$
18+
*/
19+
class sfAPCuCache extends sfCache
20+
{
21+
protected $enabled;
22+
23+
/**
24+
* Initializes this sfCache instance.
25+
*
26+
* Available options:
27+
*
28+
* * see sfCache for options available for all drivers
29+
*
30+
* @see sfCache
31+
*/
32+
public function initialize($options = array())
33+
{
34+
parent::initialize($options);
35+
36+
$this->enabled = function_exists('apcu_store') && ini_get('apc.enabled');
37+
}
38+
39+
/**
40+
* @see sfCache
41+
*
42+
* @param mixed|null $default
43+
*/
44+
public function get($key, $default = null)
45+
{
46+
if (!$this->enabled) {
47+
return $default;
48+
}
49+
50+
$value = $this->fetch($this->getOption('prefix').$key, $has);
51+
52+
return $has ? $value : $default;
53+
}
54+
55+
/**
56+
* @see sfCache
57+
*/
58+
public function has($key)
59+
{
60+
if (!$this->enabled) {
61+
return false;
62+
}
63+
64+
$this->fetch($this->getOption('prefix').$key, $has);
65+
66+
return $has;
67+
}
68+
69+
/**
70+
* @see sfCache
71+
*
72+
* @param mixed|null $lifetime
73+
*/
74+
public function set($key, $data, $lifetime = null)
75+
{
76+
if (!$this->enabled) {
77+
return true;
78+
}
79+
80+
return apcu_store($this->getOption('prefix').$key, $data, $this->getLifetime($lifetime));
81+
}
82+
83+
/**
84+
* @see sfCache
85+
*/
86+
public function remove($key)
87+
{
88+
if (!$this->enabled) {
89+
return true;
90+
}
91+
92+
return apcu_delete($this->getOption('prefix').$key);
93+
}
94+
95+
/**
96+
* @see sfCache
97+
*/
98+
public function clean($mode = sfCache::ALL)
99+
{
100+
if (!$this->enabled) {
101+
return true;
102+
}
103+
104+
if (sfCache::ALL === $mode) {
105+
return apcu_clear_cache();
106+
}
107+
}
108+
109+
/**
110+
* @see sfCache
111+
*/
112+
public function getLastModified($key)
113+
{
114+
if ($info = $this->getCacheInfo($key)) {
115+
return $info['creation_time'] + $info['ttl'] > time() ? $info['mtime'] : 0;
116+
}
117+
118+
return 0;
119+
}
120+
121+
/**
122+
* @see sfCache
123+
*/
124+
public function getTimeout($key)
125+
{
126+
if ($info = $this->getCacheInfo($key)) {
127+
return $info['creation_time'] + $info['ttl'] > time() ? $info['creation_time'] + $info['ttl'] : 0;
128+
}
129+
130+
return 0;
131+
}
132+
133+
/**
134+
* @see sfCache
135+
*/
136+
public function removePattern($pattern)
137+
{
138+
if (!$this->enabled) {
139+
return true;
140+
}
141+
142+
$infos = apcu_cache_info();
143+
if (!is_array($infos['cache_list'])) {
144+
return;
145+
}
146+
147+
$regexp = self::patternToRegexp($this->getOption('prefix').$pattern);
148+
149+
foreach ($infos['cache_list'] as $info) {
150+
if (preg_match($regexp, $info['info'])) {
151+
apcu_delete($info['info']);
152+
}
153+
}
154+
}
155+
156+
/**
157+
* Gets the cache info.
158+
*
159+
* @param string $key The cache key
160+
*
161+
* @return string
162+
*/
163+
protected function getCacheInfo($key)
164+
{
165+
if (!$this->enabled) {
166+
return false;
167+
}
168+
169+
$infos = apcu_cache_info();
170+
171+
if (is_array($infos['cache_list'])) {
172+
foreach ($infos['cache_list'] as $info) {
173+
if ($this->getOption('prefix').$key == $info['info']) {
174+
return $info;
175+
}
176+
}
177+
}
178+
179+
return null;
180+
}
181+
182+
private function fetch($key, &$success)
183+
{
184+
$has = null;
185+
$value = apcu_fetch($key, $has);
186+
// the second argument was added in APC 3.0.17. If it is still null we fall back to the value returned
187+
if (null !== $has) {
188+
$success = $has;
189+
} else {
190+
$success = false !== $value;
191+
}
192+
193+
return $value;
194+
}
195+
}

test/unit/cache/sfAPCCacheTest.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,23 @@
1313
$plan = 64;
1414
$t = new lime_test($plan);
1515

16+
if (extension_loaded('apc')) {
17+
$cacheClass = 'sfAPCCache';
18+
} elseif (extension_loaded('apcu')) {
19+
if ('5.1.22' === phpversion('apcu')) {
20+
$t->skip('APCu 5.1.22 has a regression and shouldn\'t be used', $plan);
21+
22+
return;
23+
}
24+
$cacheClass = 'sfAPCuCache';
25+
} else {
26+
$t->skip('APC or APCu must be loaded to run these tests', $plan);
27+
28+
return;
29+
}
30+
1631
try {
17-
new sfAPCCache();
32+
new $cacheClass();
1833
} catch (sfInitializationException $e) {
1934
$t->skip($e->getMessage(), $plan);
2035

@@ -34,7 +49,7 @@
3449

3550
// ->initialize()
3651
$t->diag('->initialize()');
37-
$cache = new sfAPCCache();
52+
$cache = new $cacheClass();
3853
$cache->initialize();
3954

4055
// make sure expired keys are dropped

0 commit comments

Comments
 (0)