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

codeigniter4 / CodeIgniter4 / 12673986434

08 Jan 2025 03:42PM UTC coverage: 84.455% (+0.001%) from 84.454%
12673986434

Pull #9385

github

web-flow
Merge 06e47f0ee into e475fd8fa
Pull Request #9385: refactor: Fix phpstan expr.resultUnused

20699 of 24509 relevant lines covered (84.45%)

190.57 hits per line

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

67.47
/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
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
                // Create new instance of Memcached
80
                $this->memcached = new Memcached();
14✔
81
                if ($this->config['raw']) {
14✔
82
                    $this->memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
2✔
83
                }
84

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

92
                // attempt to get status of servers
93
                $stats = $this->memcached->getStats();
14✔
94

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

104
                // Check if we can connect to the server
105
                $canConnect = $this->memcached->connect(
×
106
                    $this->config['host'],
×
107
                    $this->config['port']
×
108
                );
×
109

110
                // If we can't connect, throw a CriticalError exception
111
                if ($canConnect === false) {
×
112
                    throw new CriticalError('Cache: Memcache connection failed.');
×
113
                }
114

115
                // Add server, third parameter is persistence and defaults to TRUE.
116
                $this->memcached->addServer(
×
117
                    $this->config['host'],
×
118
                    $this->config['port'],
×
119
                    true,
×
120
                    $this->config['weight']
×
121
                );
×
122
            } else {
123
                throw new CriticalError('Cache: Not support Memcache(d) extension.');
14✔
124
            }
125
        } catch (Exception $e) {
×
126
            throw new CriticalError('Cache: Memcache(d) connection refused (' . $e->getMessage() . ').');
×
127
        }
128
    }
129

130
    /**
131
     * {@inheritDoc}
132
     */
133
    public function get(string $key)
134
    {
135
        $data = [];
2✔
136
        $key  = static::validateKey($key, $this->prefix);
2✔
137

138
        if ($this->memcached instanceof Memcached) {
2✔
139
            $data = $this->memcached->get($key);
2✔
140

141
            // check for unmatched key
142
            if ($this->memcached->getResultCode() === Memcached::RES_NOTFOUND) {
2✔
143
                return null;
2✔
144
            }
145
        } elseif ($this->memcached instanceof Memcache) {
×
146
            $flags = false;
×
147
            $data  = $this->memcached->get($key, $flags);
×
148

149
            // check for unmatched key (i.e. $flags is untouched)
150
            if ($flags === false) {
×
151
                return null;
×
152
            }
153
        }
154

155
        return is_array($data) ? $data[0] : $data;
2✔
156
    }
157

158
    /**
159
     * {@inheritDoc}
160
     */
161
    public function save(string $key, $value, int $ttl = 60)
162
    {
163
        $key = static::validateKey($key, $this->prefix);
10✔
164

165
        if (! $this->config['raw']) {
10✔
166
            $value = [
10✔
167
                $value,
10✔
168
                Time::now()->getTimestamp(),
10✔
169
                $ttl,
10✔
170
            ];
10✔
171
        }
172

173
        if ($this->memcached instanceof Memcached) {
10✔
174
            return $this->memcached->set($key, $value, $ttl);
10✔
175
        }
176

177
        if ($this->memcached instanceof Memcache) {
×
178
            return $this->memcached->set($key, $value, 0, $ttl);
×
179
        }
180

181
        return false;
×
182
    }
183

184
    /**
185
     * {@inheritDoc}
186
     */
187
    public function delete(string $key)
188
    {
189
        $key = static::validateKey($key, $this->prefix);
14✔
190

191
        return $this->memcached->delete($key);
14✔
192
    }
193

194
    /**
195
     * {@inheritDoc}
196
     *
197
     * @return never
198
     */
199
    public function deleteMatching(string $pattern)
200
    {
201
        throw new BadMethodCallException('The deleteMatching method is not implemented for Memcached. You must select File, Redis or Predis handlers to use it.');
1✔
202
    }
203

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

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

215
        return $this->memcached->increment($key, $offset, $offset, 60);
1✔
216
    }
217

218
    /**
219
     * {@inheritDoc}
220
     */
221
    public function decrement(string $key, int $offset = 1)
222
    {
223
        if (! $this->config['raw']) {
1✔
224
            return false;
1✔
225
        }
226

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

229
        // FIXME: third parameter isn't other handler actions.
230

231
        return $this->memcached->decrement($key, $offset, $offset, 60);
1✔
232
    }
233

234
    /**
235
     * {@inheritDoc}
236
     */
237
    public function clean()
238
    {
239
        return $this->memcached->flush();
1✔
240
    }
241

242
    /**
243
     * {@inheritDoc}
244
     */
245
    public function getCacheInfo()
246
    {
247
        return $this->memcached->getStats();
1✔
248
    }
249

250
    /**
251
     * {@inheritDoc}
252
     */
253
    public function getMetaData(string $key)
254
    {
255
        $key    = static::validateKey($key, $this->prefix);
3✔
256
        $stored = $this->memcached->get($key);
3✔
257

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

263
        [$data, $time, $limit] = $stored;
2✔
264

265
        return [
2✔
266
            'expire' => $limit > 0 ? $time + $limit : null,
2✔
267
            'mtime'  => $time,
2✔
268
            'data'   => $data,
2✔
269
        ];
2✔
270
    }
271

272
    /**
273
     * {@inheritDoc}
274
     */
275
    public function isSupported(): bool
276
    {
277
        return extension_loaded('memcached') || extension_loaded('memcache');
1✔
278
    }
279
}
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

© 2026 Coveralls, Inc