1 |
36485
|
argiro.kok
|
# Predis #
|
2 |
|
|
|
3 |
|
|
[![Latest Stable Version](https://poser.pugx.org/predis/predis/v/stable.png)](https://packagist.org/packages/predis/predis)
|
4 |
|
|
[![Total Downloads](https://poser.pugx.org/predis/predis/downloads.png)](https://packagist.org/packages/predis/predis)
|
5 |
|
|
|
6 |
|
|
Predis is a flexible and feature-complete [Redis](http://redis.io) client library for PHP >= 5.3.
|
7 |
|
|
|
8 |
|
|
By default Predis does not require any additional C extension, but it can be optionally paired with
|
9 |
|
|
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of serializing and parsing the
|
10 |
|
|
Redis protocol. An asynchronous implementation of the client, albeit experimental, is also available
|
11 |
|
|
through [Predis\Async](https://github.com/nrk/predis-async).
|
12 |
|
|
|
13 |
|
|
Predis can be used with [HHVM](http://www.hhvm.com) >= 2.4.0, but there are no guarantees you will
|
14 |
|
|
not run into unexpected issues (especially with the JIT compiler enabled via `Eval.Jit = true`) due
|
15 |
|
|
to HHVM being still under heavy development, thus unstable and not yet 100% compatible with PHP.
|
16 |
|
|
|
17 |
|
|
More details about the project can be found in our [frequently asked questions](FAQ.md) section or
|
18 |
|
|
on the online [wiki](https://github.com/nrk/predis/wiki).
|
19 |
|
|
|
20 |
|
|
|
21 |
|
|
## Main features ##
|
22 |
|
|
|
23 |
|
|
- Wide range of Redis versions supported (from __1.2__ to __2.8__ and unstable) using profiles.
|
24 |
|
|
- Clustering via client-side sharding using consistent hashing or custom distributors.
|
25 |
|
|
- Smart support for [redis-cluster](http://redis.io/topics/cluster-spec) (Redis >= 3.0).
|
26 |
|
|
- Support for master-slave replication configurations (write on master, read from slaves).
|
27 |
|
|
- Transparent key prefixing for all Redis commands.
|
28 |
|
|
- Command pipelining (works on both single and aggregate connections).
|
29 |
|
|
- Abstraction for Redis transactions (Redis >= 2.0) supporting CAS operations (Redis >= 2.2).
|
30 |
|
|
- Abstraction for Lua scripting (Redis >= 2.6) with automatic switching between `EVALSHA` or `EVAL`.
|
31 |
|
|
- Abstraction for `SCAN`, `SSCAN`, `ZSCAN` and `HSCAN` (Redis >= 2.8) based on PHP iterators.
|
32 |
|
|
- Connections to Redis are established lazily by the client upon the first command.
|
33 |
|
|
- Support for both TCP/IP and UNIX domain sockets and persistent connections.
|
34 |
|
|
- Support for [Webdis](http://webd.is) (both `ext-curl` and `ext-phpiredis` are needed).
|
35 |
|
|
- Support for custom connection classes for providing different network or protocol backends.
|
36 |
|
|
- Flexible system for defining and registering custom sets of supported commands or profiles.
|
37 |
|
|
|
38 |
|
|
|
39 |
|
|
## How to use Predis ##
|
40 |
|
|
|
41 |
|
|
Predis is available on [Packagist](http://packagist.org/packages/predis/predis) which allows a quick
|
42 |
|
|
installation using [Composer](http://packagist.org/about-composer). Alternatively, the library can
|
43 |
|
|
be found on our [own PEAR channel](http://pear.nrk.io) for a more traditional installation via PEAR.
|
44 |
|
|
Ultimately, archives of each release are [available on GitHub](https://github.com/nrk/predis/tags).
|
45 |
|
|
|
46 |
|
|
|
47 |
|
|
### Loading the library ###
|
48 |
|
|
|
49 |
|
|
Predis relies on the autoloading features of PHP to load its files when needed and complies with the
|
50 |
|
|
[PSR-0 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) which makes
|
51 |
|
|
it compatible with most PHP frameworks. Autoloading is handled automatically when dependencies are
|
52 |
|
|
managed using Composer, but you can also leverage its own autoloader if you are going to use it in a
|
53 |
|
|
project or script without any PSR-0 compliant autoloading facility:
|
54 |
|
|
|
55 |
|
|
```php
|
56 |
|
|
// Prepend a base path if Predis is not available in your "include_path".
|
57 |
|
|
require 'Predis/Autoloader.php';
|
58 |
|
|
|
59 |
|
|
Predis\Autoloader::register();
|
60 |
|
|
```
|
61 |
|
|
|
62 |
|
|
It is possible to easily create a [phar](http://www.php.net/manual/en/intro.phar.php) archive from
|
63 |
|
|
the repository just by launching `bin/create-phar`. The generated phar contains a stub defining an
|
64 |
|
|
autoloader function for Predis, so you just need to require the phar to start using the library.
|
65 |
|
|
Alternatively, it is also possible to generate one single PHP file that holds every class like older
|
66 |
|
|
versions of Predis by launching `bin/create-single-file`, but this practice __is not__ encouraged.
|
67 |
|
|
|
68 |
|
|
|
69 |
|
|
### Connecting to Redis ###
|
70 |
|
|
|
71 |
|
|
When not specifying any connection parameter to create a new client, Predis assumes `127.0.0.1` and
|
72 |
|
|
`6379` as the default host and port and uses a connection timeout of 5 seconds:
|
73 |
|
|
|
74 |
|
|
```php
|
75 |
|
|
$client = new Predis\Client();
|
76 |
|
|
$client->set('foo', 'bar');
|
77 |
|
|
$value = $client->get('foo');
|
78 |
|
|
```
|
79 |
|
|
|
80 |
|
|
Connection parameters can be supplied either in the form of URI strings or named arrays. While the
|
81 |
|
|
latter is the preferred way to supply parameters, URI strings can be useful for quick configurations
|
82 |
|
|
or when parameters are read from a non-structured source:
|
83 |
|
|
|
84 |
|
|
```php
|
85 |
|
|
// Named array of connection parameters:
|
86 |
|
|
$client = new Predis\Client([
|
87 |
|
|
'scheme' => 'tcp',
|
88 |
|
|
'host' => '10.0.0.1',
|
89 |
|
|
'port' => 6379,
|
90 |
|
|
]);
|
91 |
|
|
|
92 |
|
|
// Same set of parameters, but using an URI string:
|
93 |
|
|
$client = new Predis\Client('tcp://10.0.0.1:6379');
|
94 |
|
|
```
|
95 |
|
|
|
96 |
|
|
When an array of connections parameters is provided, Predis automatically works in clustering mode
|
97 |
|
|
using client-side sharding. Both named arrays and URI strings can be mixed for providing each node
|
98 |
|
|
configuration:
|
99 |
|
|
|
100 |
|
|
```php
|
101 |
|
|
$client = new Predis\Client([
|
102 |
|
|
'tcp://10.0.0.1?alias=first-node',
|
103 |
|
|
['host' => '10.0.0.2', 'alias' => 'second-node'],
|
104 |
|
|
]);
|
105 |
|
|
```
|
106 |
|
|
|
107 |
|
|
The actual list of supported connection parameters can vary depending on each connection backend so
|
108 |
|
|
it is recommended to refer to their specific documentation for details.
|
109 |
|
|
|
110 |
|
|
|
111 |
|
|
### Client configuration ###
|
112 |
|
|
|
113 |
|
|
Various aspects of the client can be easily configured by passing options to the second argument of
|
114 |
|
|
`Predis\Client::__construct()`. Options are managed using a mini DI-alike container and their values
|
115 |
|
|
are usually lazily initialized only when needed. Predis by default supports the following options:
|
116 |
|
|
|
117 |
|
|
- `profile`: which profile to use in order to match a specific version of Redis.
|
118 |
|
|
- `prefix`: a prefix string that is automatically applied to keys found in commands.
|
119 |
|
|
- `exceptions`: whether the client should throw or return responses upon Redis errors.
|
120 |
|
|
- `connections`: connection backends or a connection factory to be used by the client.
|
121 |
|
|
- `cluster`: which backend to use for clustering (predis, redis or custom configuration).
|
122 |
|
|
- `replication`: which backend to use for replication (predis or custom configuration).
|
123 |
|
|
|
124 |
|
|
Users can provide custom option values, they are stored in the options container and can be accessed
|
125 |
|
|
later through the library.
|
126 |
|
|
|
127 |
|
|
|
128 |
|
|
### Aggregate connections ###
|
129 |
|
|
|
130 |
|
|
Predis is able to aggregate multiple connections which is the base for clustering and replication.
|
131 |
|
|
By default the client implements clustering using either client-side sharding (default) or a Redis
|
132 |
|
|
backed solution using [redis-cluster](http://redis.io/topics/cluster-tutorial). As for replication,
|
133 |
|
|
Predis can handle single-master and multiple-slaves setups by executing read operations on slaves
|
134 |
|
|
and switching to the master for write operations. The replication behaviour is fully configurable.
|
135 |
|
|
|
136 |
|
|
|
137 |
|
|
### Command pipelines ###
|
138 |
|
|
|
139 |
|
|
Pipelining can help with performances when many commands need to be sent to a server by reducing the
|
140 |
|
|
latency introduced by network round-trip timings. Pipelining also works with aggregate connections.
|
141 |
|
|
The client can execute the pipeline inside a callable block or return a pipeline instance with the
|
142 |
|
|
ability to chain commands thanks to its fluent interface:
|
143 |
|
|
|
144 |
|
|
```php
|
145 |
|
|
// Executes a pipeline inside a given callable block:
|
146 |
|
|
$responses = $client->pipeline(function ($pipe) {
|
147 |
|
|
for ($i = 0; $i < 1000; $i++) {
|
148 |
|
|
$pipe->set("key:$i", str_pad($i, 4, '0', 0));
|
149 |
|
|
$pipe->get("key:$i");
|
150 |
|
|
}
|
151 |
|
|
});
|
152 |
|
|
|
153 |
|
|
// Returns a pipeline instance with fluent interface:
|
154 |
|
|
$responses = $client->pipeline()->set('foo', 'bar')->get('foo')->execute();
|
155 |
|
|
```
|
156 |
|
|
|
157 |
|
|
|
158 |
|
|
### Transactions ###
|
159 |
|
|
|
160 |
|
|
The client provides an abstraction for Redis transactions based on `MULTI` and `EXEC` with a similar
|
161 |
|
|
interface to command pipelines:
|
162 |
|
|
|
163 |
|
|
```php
|
164 |
|
|
// Executes a transaction inside a given callable block:
|
165 |
|
|
$responses = $client->transaction(function ($tx) {
|
166 |
|
|
$tx->set('foo', 'bar');
|
167 |
|
|
$tx->get('foo');
|
168 |
|
|
});
|
169 |
|
|
|
170 |
|
|
// Returns a transaction instance with fluent interface:
|
171 |
|
|
$responses = $client->transaction()->set('foo', 'bar')->get('foo')->execute();
|
172 |
|
|
```
|
173 |
|
|
|
174 |
|
|
This abstraction can perform check-and-set operations thanks to `WATCH` and `UNWATCH` and provides
|
175 |
|
|
automatic retries of transactions aborted by Redis when `WATCH`ed keys are touched. For an example
|
176 |
|
|
of a transaction using CAS you can see [the following example](examples/TransactionWithCAS.php).
|
177 |
|
|
|
178 |
|
|
__NOTE__: the method `transaction()` is available since `v0.8.5`, older versions used `multiExec()`
|
179 |
|
|
for the same purpose but it has been deprecated and will be removed in the next major release.
|
180 |
|
|
|
181 |
|
|
|
182 |
|
|
### Customizable connection backends ###
|
183 |
|
|
|
184 |
|
|
Predis can use different connection backends to connect to Redis. Two of them leverage a third party
|
185 |
|
|
extension such as [phpiredis](https://github.com/nrk/phpiredis) resulting in major performance gains
|
186 |
|
|
especially when dealing with big multibulk responses. While one is based on PHP streams, the other
|
187 |
|
|
is based on socket resources provided by `ext-socket`. Both support TCP/IP or UNIX domain sockets:
|
188 |
|
|
|
189 |
|
|
```php
|
190 |
|
|
$client = new Predis\Client('tcp://127.0.0.1', [
|
191 |
|
|
'connections' => [
|
192 |
|
|
'tcp' => 'Predis\Connection\PhpiredisStreamConnection', // PHP streams
|
193 |
|
|
'unix' => 'Predis\Connection\PhpiredisConnection', // ext-socket
|
194 |
|
|
],
|
195 |
|
|
]);
|
196 |
|
|
```
|
197 |
|
|
|
198 |
|
|
Developers can create their own connection classes to add support for new network backends, extend
|
199 |
|
|
existing ones or provide completely different implementations. Connection classes must implement
|
200 |
|
|
`Predis\Connection\SingleConnectionInterface` or extend `Predis\Connection\AbstractConnection`:
|
201 |
|
|
|
202 |
|
|
```php
|
203 |
|
|
class MyConnectionClass implements Predis\Connection\SingleConnectionInterface
|
204 |
|
|
{
|
205 |
|
|
// Implementation goes here...
|
206 |
|
|
}
|
207 |
|
|
|
208 |
|
|
// Use MyConnectionClass to handle connections for the `tcp` scheme:
|
209 |
|
|
$client = new Predis\Client('tcp://127.0.0.1', [
|
210 |
|
|
'connections' => ['tcp' => 'MyConnectionClass'],
|
211 |
|
|
]);
|
212 |
|
|
```
|
213 |
|
|
|
214 |
|
|
For a more in-depth insight on how to create new connection backends you can refer to the actual
|
215 |
|
|
implementation of the standard connection classes available in the `Predis\Connection` namespace.
|
216 |
|
|
|
217 |
|
|
|
218 |
|
|
### Adding support for new commands ###
|
219 |
|
|
|
220 |
|
|
While we try to update Predis to stay up to date with all the commands available in Redis, you might
|
221 |
|
|
prefer to stick with an older version of the library or provide a different way to filter arguments
|
222 |
|
|
or parse responses for specific commands. To achieve that, Predis provides the ability to implement
|
223 |
|
|
new command classes to define or override commands in the server profiles used by the client:
|
224 |
|
|
|
225 |
|
|
```php
|
226 |
|
|
// Define a new command by extending Predis\Command\AbstractCommand:
|
227 |
|
|
class BrandNewRedisCommand extends Predis\Command\AbstractCommand
|
228 |
|
|
{
|
229 |
|
|
public function getId()
|
230 |
|
|
{
|
231 |
|
|
return 'NEWCMD';
|
232 |
|
|
}
|
233 |
|
|
}
|
234 |
|
|
|
235 |
|
|
// Inject your command in the current profile:
|
236 |
|
|
$client = new Predis\Client();
|
237 |
|
|
$client->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
|
238 |
|
|
|
239 |
|
|
$response = $client->newcmd();
|
240 |
|
|
```
|
241 |
|
|
|
242 |
|
|
|
243 |
|
|
### Scriptable commands ###
|
244 |
|
|
|
245 |
|
|
A scriptable command is just an abstraction for [Lua scripting](http://redis.io/commands/eval) that
|
246 |
|
|
aims to simplify the usage of scripting with Redis >= 2.6. Scriptable commands can be registered in
|
247 |
|
|
the server profile used by the client and are accessible as if they were plain Redis commands, but
|
248 |
|
|
they define a Lua script that gets transmitted to Redis for remote execution. Internally, scriptable
|
249 |
|
|
commands use by default [EVALSHA](http://redis.io/commands/evalsha) and identify a Lua script by its
|
250 |
|
|
SHA1 hash to save bandwidth but [EVAL](http://redis.io/commands/eval) is automatically preferred as
|
251 |
|
|
a fall back when needed:
|
252 |
|
|
|
253 |
|
|
```php
|
254 |
|
|
// Define a new scriptable command by extending Predis\Command\ScriptedCommand:
|
255 |
|
|
class ListPushRandomValue extends Predis\Command\ScriptedCommand
|
256 |
|
|
{
|
257 |
|
|
public function getKeysCount()
|
258 |
|
|
{
|
259 |
|
|
return 1;
|
260 |
|
|
}
|
261 |
|
|
|
262 |
|
|
public function getScript()
|
263 |
|
|
{
|
264 |
|
|
return <<<LUA
|
265 |
|
|
math.randomseed(ARGV[1])
|
266 |
|
|
local rnd = tostring(math.random())
|
267 |
|
|
redis.call('lpush', KEYS[1], rnd)
|
268 |
|
|
return rnd
|
269 |
|
|
LUA;
|
270 |
|
|
}
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
// Inject your scriptable command in the current profile:
|
274 |
|
|
$client = new Predis\Client();
|
275 |
|
|
$client->getProfile()->defineCommand('lpushrand', 'ListPushRandomValue');
|
276 |
|
|
|
277 |
|
|
$response = $client->lpushrand('random_values', $seed = mt_rand());
|
278 |
|
|
```
|
279 |
|
|
|
280 |
|
|
|
281 |
|
|
## Development ##
|
282 |
|
|
|
283 |
|
|
|
284 |
|
|
### Reporting bugs and contributing code ###
|
285 |
|
|
|
286 |
|
|
Contributions to Predis are highly appreciated either in the form of pull requests for new features,
|
287 |
|
|
bug fixes, or just bug reports. We only ask you to adhere to a [basic set of rules](CONTRIBUTING.md)
|
288 |
|
|
before submitting your changes or filing bugs on the issue tracker to make it easier for everyone to
|
289 |
|
|
stay consistent while working on the project.
|
290 |
|
|
|
291 |
|
|
|
292 |
|
|
### Test suite ###
|
293 |
|
|
|
294 |
|
|
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running
|
295 |
|
|
in production environments or containing data you are interested in!
|
296 |
|
|
|
297 |
|
|
Predis has a comprehensive test suite covering every aspect of the library. This test suite performs
|
298 |
|
|
integration tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct
|
299 |
|
|
behaviour of the implementation of each command and automatically skips commands not defined in the
|
300 |
|
|
specified Redis profile. If you do not have Redis up and running, integration tests can be disabled.
|
301 |
|
|
By default the test suite is configured to execute integration tests using the profile for Redis 2.8
|
302 |
|
|
(which is the current stable version of Redis) but can optionally target a Redis instance built from
|
303 |
|
|
the `unstable` branch by modifying `phpunit.xml` and setting `REDIS_SERVER_VERSION` to `dev` so that
|
304 |
|
|
the development server profile will be used. You can refer to [the tests README](tests/README.md)
|
305 |
|
|
for more detailed information about testing Predis.
|
306 |
|
|
|
307 |
|
|
Predis uses Travis CI for continuous integration and the history for past and current builds can be
|
308 |
|
|
found [on its project page](http://travis-ci.org/nrk/predis).
|
309 |
|
|
|
310 |
|
|
|
311 |
|
|
## Other ##
|
312 |
|
|
|
313 |
|
|
|
314 |
|
|
### Project related links ###
|
315 |
|
|
|
316 |
|
|
- [Source code](https://github.com/nrk/predis)
|
317 |
|
|
- [Wiki](https://wiki.github.com/nrk/predis)
|
318 |
|
|
- [Issue tracker](https://github.com/nrk/predis/issues)
|
319 |
|
|
- [PEAR channel](http://pear.nrk.io)
|
320 |
|
|
|
321 |
|
|
|
322 |
|
|
### Author ###
|
323 |
|
|
|
324 |
|
|
- [Daniele Alessandri](mailto:suppakilla@gmail.com) ([twitter](http://twitter.com/JoL1hAHN))
|
325 |
|
|
|
326 |
|
|
|
327 |
|
|
### License ###
|
328 |
|
|
|
329 |
|
|
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
|