• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codeigniter4 / CodeIgniter4 / 15880832508

25 Jun 2025 03:39PM UTC coverage: 84.209% (+0.007%) from 84.202%
15880832508

push

github

web-flow
refactor: fix various phpstan errors in Cache (#9610)

16 of 30 new or added lines in 6 files covered. (53.33%)

2 existing lines in 1 file now uncovered.

20793 of 24692 relevant lines covered (84.21%)

192.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.89
/system/Cache/Handlers/MemcachedHandler.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\Cache\Handlers;
15

16
use CodeIgniter\Exceptions\BadMethodCallException;
17
use CodeIgniter\Exceptions\CriticalError;
18
use CodeIgniter\I18n\Time;
19
use Config\Cache;
20
use Exception;
21
use Memcache;
22
use Memcached;
23

24
/**
25
 * Mamcached cache handler
26
 *
27
 * @see \CodeIgniter\Cache\Handlers\MemcachedHandlerTest
28
 */
29
class MemcachedHandler extends BaseHandler
30
{
31
    /**
32
     * The memcached object
33
     *
34
     * @var Memcache|Memcached
35
     */
36
    protected $memcached;
37

38
    /**
39
     * Memcached Configuration
40
     *
41
     * @var array{host: string, port: int, weight: int, raw: bool}
42
     */
43
    protected $config = [
44
        'host'   => '127.0.0.1',
45
        'port'   => 11211,
46
        'weight' => 1,
47
        'raw'    => false,
48
    ];
49

50
    /**
51
     * Note: Use `CacheFactory::getHandler()` to instantiate.
52
     */
53
    public function __construct(Cache $config)
54
    {
55
        $this->prefix = $config->prefix;
14✔
56

57
        $this->config = array_merge($this->config, $config->memcached);
14✔
58
    }
59

60
    /**
61
     * Closes the connection to Memcache(d) if present.
62
     */
63
    public function __destruct()
64
    {
65
        if ($this->memcached instanceof Memcached) {
2✔
66
            $this->memcached->quit();
2✔
67
        } elseif ($this->memcached instanceof Memcache) {
×
68
            $this->memcached->close();
×
69
        }
70
    }
71

72
    /**
73
     * {@inheritDoc}
74
     */
75
    public function initialize()
76
    {
77
        try {
78
            if (class_exists(Memcached::class)) {
14✔
79
                $this->memcached = new Memcached();
14✔
80

81
                if ($this->config['raw']) {
14✔
82
                    $this->memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
2✔
83
                }
84

85
                $this->memcached->addServer(
14✔
86
                    $this->config['host'],
14✔
87
                    $this->config['port'],
14✔
88
                    $this->config['weight'],
14✔
89
                );
14✔
90

91
                $stats = $this->memcached->getStats();
14✔
92

93
                // $stats should be an associate array with a key in the format of host:port.
94
                // If it doesn't have the key, we know the server is not working as expected.
95
                if (! is_array($stats) || ! isset($stats[$this->config['host'] . ':' . $this->config['port']])) {
14✔
96
                    throw new CriticalError('Cache: Memcached connection failed.');
×
97
                }
98
            } elseif (class_exists(Memcache::class)) {
×
UNCOV
99
                $this->memcached = new Memcache();
×
100

NEW
101
                if (! $this->memcached->connect($this->config['host'], $this->config['port'])) {
×
102
                    throw new CriticalError('Cache: Memcache connection failed.');
×
103
                }
104

UNCOV
105
                $this->memcached->addServer(
×
106
                    $this->config['host'],
×
107
                    $this->config['port'],
×
108
                    true,
×
109
                    $this->config['weight'],
×
110
                );
×
111
            } else {
112
                throw new CriticalError('Cache: Not support Memcache(d) extension.');
14✔
113
            }
114
        } catch (Exception $e) {
×
115
            throw new CriticalError('Cache: Memcache(d) connection refused (' . $e->getMessage() . ').');
×
116
        }
117
    }
118

119
    /**
120
     * {@inheritDoc}
121
     */
122
    public function get(string $key)
123
    {
124
        $data = [];
2✔
125
        $key  = static::validateKey($key, $this->prefix);
2✔
126

127
        if ($this->memcached instanceof Memcached) {
2✔
128
            $data = $this->memcached->get($key);
2✔
129

130
            // check for unmatched key
131
            if ($this->memcached->getResultCode() === Memcached::RES_NOTFOUND) {
2✔
132
                return null;
2✔
133
            }
134
        } elseif ($this->memcached instanceof Memcache) {
×
135
            $flags = false;
×
136
            $data  = $this->memcached->get($key, $flags);
×
137

138
            // check for unmatched key (i.e. $flags is untouched)
139
            if ($flags === false) {
×
140
                return null;
×
141
            }
142
        }
143

144
        return is_array($data) ? $data[0] : $data;
2✔
145
    }
146

147
    /**
148
     * {@inheritDoc}
149
     */
150
    public function save(string $key, $value, int $ttl = 60)
151
    {
152
        $key = static::validateKey($key, $this->prefix);
10✔
153

154
        if (! $this->config['raw']) {
10✔
155
            $value = [
10✔
156
                $value,
10✔
157
                Time::now()->getTimestamp(),
10✔
158
                $ttl,
10✔
159
            ];
10✔
160
        }
161

162
        if ($this->memcached instanceof Memcached) {
10✔
163
            return $this->memcached->set($key, $value, $ttl);
10✔
164
        }
165

166
        if ($this->memcached instanceof Memcache) {
×
167
            return $this->memcached->set($key, $value, 0, $ttl);
×
168
        }
169

170
        return false;
×
171
    }
172

173
    /**
174
     * {@inheritDoc}
175
     */
176
    public function delete(string $key)
177
    {
178
        $key = static::validateKey($key, $this->prefix);
14✔
179

180
        return $this->memcached->delete($key);
14✔
181
    }
182

183
    /**
184
     * {@inheritDoc}
185
     *
186
     * @return never
187
     */
188
    public function deleteMatching(string $pattern)
189
    {
190
        throw new BadMethodCallException('The deleteMatching method is not implemented for Memcached. You must select File, Redis or Predis handlers to use it.');
1✔
191
    }
192

193
    /**
194
     * {@inheritDoc}
195
     */
196
    public function increment(string $key, int $offset = 1)
197
    {
198
        if (! $this->config['raw']) {
1✔
199
            return false;
1✔
200
        }
201

202
        $key = static::validateKey($key, $this->prefix);
1✔
203

204
        return $this->memcached->increment($key, $offset, $offset, 60);
1✔
205
    }
206

207
    /**
208
     * {@inheritDoc}
209
     */
210
    public function decrement(string $key, int $offset = 1)
211
    {
212
        if (! $this->config['raw']) {
1✔
213
            return false;
1✔
214
        }
215

216
        $key = static::validateKey($key, $this->prefix);
1✔
217

218
        // FIXME: third parameter isn't other handler actions.
219

220
        return $this->memcached->decrement($key, $offset, $offset, 60);
1✔
221
    }
222

223
    /**
224
     * {@inheritDoc}
225
     */
226
    public function clean()
227
    {
228
        return $this->memcached->flush();
1✔
229
    }
230

231
    /**
232
     * {@inheritDoc}
233
     */
234
    public function getCacheInfo()
235
    {
236
        return $this->memcached->getStats();
1✔
237
    }
238

239
    /**
240
     * {@inheritDoc}
241
     */
242
    public function getMetaData(string $key)
243
    {
244
        $key    = static::validateKey($key, $this->prefix);
3✔
245
        $stored = $this->memcached->get($key);
3✔
246

247
        // if not an array, don't try to count for PHP7.2
248
        if (! is_array($stored) || count($stored) !== 3) {
3✔
249
            return false; // @TODO This will return null in a future release
1✔
250
        }
251

252
        [$data, $time, $limit] = $stored;
2✔
253

254
        return [
2✔
255
            'expire' => $limit > 0 ? $time + $limit : null,
2✔
256
            'mtime'  => $time,
2✔
257
            'data'   => $data,
2✔
258
        ];
2✔
259
    }
260

261
    /**
262
     * {@inheritDoc}
263
     */
264
    public function isSupported(): bool
265
    {
266
        return extension_loaded('memcached') || extension_loaded('memcache');
14✔
267
    }
268
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc