mirror of
https://github.com/predis/predis.git
synced 2026-08-19 18:52:50 +00:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 239864d9a0 | |||
| b006d2306c | |||
| 34e394cc10 | |||
| 79539c3bcf | |||
| 74817b5596 | |||
| f967ecd66b | |||
| 261d0b824f | |||
| b77da8476c | |||
| 3fbd29d00b | |||
| 8373663486 | |||
| 18853d1dbb | |||
| 1da827c0ae | |||
| aa8fd5cea4 | |||
| 8d353cc223 | |||
| 0a580c9d1b | |||
| 58d1cc12dc | |||
| a8862f0fdd | |||
| e148dc831a | |||
| c4b592298c | |||
| 0e3b105959 | |||
| 749bbfe0e3 | |||
| c2ae1c612e | |||
| a85f89e2c7 | |||
| dbb802f0f1 | |||
| 64b79511bd | |||
| 5a9e747b01 | |||
| cb0fbd01b4 | |||
| 83df2ef11c | |||
| c94e5d3a10 | |||
| c90fbfc0ff | |||
| 21d6f0e7c6 | |||
| f4a950b275 | |||
| 5ec51c899f | |||
| e1d700dd0c | |||
| 809f76a7b3 | |||
| ab6cbe7e10 | |||
| 80bcb9f475 | |||
| c8e671a42a | |||
| 838e6af403 | |||
| ba2ffb612a | |||
| fdaf73987b | |||
| 50f8922df2 | |||
| 60733eb5c9 | |||
| a13dd4e180 | |||
| 1678e486b1 | |||
| 5f2eea628e | |||
| 0f01b89d44 | |||
| 9d0201ed9e | |||
| 0cead0245d | |||
| 0a4eed1dff | |||
| d2debfd43e | |||
| 9a1884d960 | |||
| a6dd685f8d | |||
| f499d5695a | |||
| 23c4b95a0b | |||
| 80cb31514a | |||
| 6306509086 | |||
| 2aab474670 | |||
| d628c0f23b | |||
| ad92618003 | |||
| 0fb7674762 | |||
| e778baa491 | |||
| d88a280977 | |||
| eb6cbef4e7 | |||
| 2aa771004d | |||
| 43bf3096a0 | |||
| 317fa42891 | |||
| b45f87caf2 | |||
| b7cba07014 | |||
| 56627f30f8 | |||
| 9d4524cae7 | |||
| fd1c6f244f | |||
| aa4d0a05ac | |||
| d45b5f7ec8 | |||
| 87ca5a1a49 | |||
| e5ec950a11 | |||
| 3f2c2b9031 | |||
| 88ea08fe83 | |||
| bd48225edc | |||
| ea9809d4e8 | |||
| 09cb6677e2 | |||
| c32f6c7152 | |||
| 78fd475747 | |||
| 86a4343e59 | |||
| ecf1cc07e5 | |||
| 2fc1ea88cd | |||
| 72e9187662 | |||
| 98410bbcaa | |||
| 5ea1d6fe92 | |||
| 73780da52d | |||
| 381023ad8f | |||
| c3c819cc9c | |||
| 987f27556f | |||
| a9b42924e5 | |||
| e4e2238f34 | |||
| e1f6c8644f | |||
| d16a1c8705 | |||
| 32aff28ef5 | |||
| eb906bb29c | |||
| 33ef043b8e | |||
| 973c9a7031 | |||
| db55fae961 | |||
| 5192005862 | |||
| cdc6075b01 | |||
| 623d1cc1a2 | |||
| d53069f096 | |||
| 8565a42605 | |||
| aac811f897 | |||
| 4e664c6c90 | |||
| b1a51b2ef9 | |||
| de02c81398 |
+11
-1
@@ -3,6 +3,8 @@ php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
branches:
|
||||
except:
|
||||
- v0.5
|
||||
@@ -10,4 +12,12 @@ branches:
|
||||
- php5.2_backport
|
||||
- documentation
|
||||
services: redis-server
|
||||
script: phpunit -c phpunit.xml.travisci
|
||||
before_script:
|
||||
- composer self-update
|
||||
- composer install --no-interaction --prefer-source --dev
|
||||
script:
|
||||
- vendor/bin/phpunit -c phpunit.xml.travisci
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
fast_finish: true
|
||||
|
||||
+86
-26
@@ -1,8 +1,43 @@
|
||||
v0.8.5 (2013-xx-xx)
|
||||
===============================================================================
|
||||
v0.8.6 (2014-07-15)
|
||||
================================================================================
|
||||
|
||||
- Added `2.8` in the server profiles aliases list for the upcoming Redis 2.8.
|
||||
`2.6` is still the default server profile. `dev` now targets Redis 3.0.
|
||||
- Redis 2.8 is not the default server profile as there are no changes that would
|
||||
break compatibility with previous releases.
|
||||
|
||||
- Added `PFADD`, `PFCOUNT`, `PFMERGE` to the server profile for Redis 2.8 for
|
||||
handling the HyperLogLog data structure introduced in Redis 2.8.9.
|
||||
|
||||
- Added `ZLEXCOUNT`, `ZRANGEBYLEX`, `ZREMRANGEBYLEX` to the server profile for
|
||||
Redis 2.8 for handling lexicographic operations on members of sorted sets.
|
||||
|
||||
- Added support for key hash tags when using redis-cluster (Redis 3.0.0b1).
|
||||
|
||||
- __FIX__: minor tweaks to make Predis compatible with HHVM >= 2.4.0.
|
||||
|
||||
- __FIX__: responses to `INFO` are now properly parsed and will not break when
|
||||
redis sentinel is being used (ISSUE #154).
|
||||
|
||||
- __FIX__: added missing support for `INCRBYFLOAT` in cluster and replication
|
||||
configurations (ISSUE #159).
|
||||
|
||||
- __FIX__: fix parsing of the output of `CLUSTER NODES` to fetch the slots map
|
||||
from a node when redis-cluster has slaves in its configuration (ISSUE #165).
|
||||
|
||||
- __FIX__: prevent a stack overflow when iterating over large Redis collections
|
||||
using our abstraction for cursor-based iterators (ISSUE #182).
|
||||
|
||||
- __FIX__: properly discards transactions when the server immediately returns an
|
||||
error response (e.g. -OOM or -ERR on invalid arguments for a command) instead
|
||||
of a +QUEUED response (ISSUE #187).
|
||||
|
||||
- Upgraded to PHPUnit 4.* for the test suite.
|
||||
|
||||
|
||||
v0.8.5 (2014-01-16)
|
||||
================================================================================
|
||||
|
||||
- Added `2.8` in the server profiles aliases list for Redis 2.8. `2.6` is still
|
||||
the default server profile and `dev` now targets Redis 3.0.
|
||||
|
||||
- Added `SCAN`, `SSCAN`, `ZSCAN`, `HSCAN` to the server profile for Redis 2.8.
|
||||
|
||||
@@ -14,14 +49,39 @@ v0.8.5 (2013-xx-xx)
|
||||
- hashes (cursor-based iterator using `HSCAN`)
|
||||
- lists (plain iterator using `LRANGE`)
|
||||
|
||||
- `Predis\Client::pubSubLoop()` should now be used instead of the deprecated
|
||||
`Predis\Client::pubSub()` (which still works like usual to avoid B/C breaks).
|
||||
`Predis\Client::pubSub()` will change in the next major version of Predis to
|
||||
support the new PUBSUB command recently added in Redis 2.8.
|
||||
- It is now possible to execute "raw commands" using `Predis\Command\RawCommand`
|
||||
and a variable list of command arguments. Input arguments are not filtered and
|
||||
responses are not parsed, which means arguments must follow the signature of
|
||||
the command as defined by Redis and complex responses are left untouched.
|
||||
|
||||
- URI parsing for connection parameters has been improved and has slightly less
|
||||
overhead when the number of fields in the querystring grows. New features are:
|
||||
|
||||
- Parsing does not break when value of a field contains one or more "=".
|
||||
- Repeated fieldnames using [] produce an array of values.
|
||||
- Empty or incomplete "key=value" pairs result in an empty string for "key".
|
||||
|
||||
- Various improvements and fixes to the redis-cluster connection backend:
|
||||
|
||||
- __FIX__: the `ASKING` command is sent upon -ASK redirections.
|
||||
- An updated slots-map can be fetched from nodes using the `CLUSTER NODES`
|
||||
command. By default this is a manual operation but can be enabled to get
|
||||
automatically done upon -MOVED redirections.
|
||||
- It is possible to specify a common set of connection parameters that are
|
||||
applied to connections created on the fly upon redirections to nodes not
|
||||
part of the initial pool.
|
||||
|
||||
- List of deprecated methods:
|
||||
|
||||
- `Predis\Client::multiExec()`: superseded by `Predis\Client::transaction()`
|
||||
and to be removed in the next major release.
|
||||
- `Predis\Client::pubSub()`: superseded by `Predis\Client::pubSubLoop()` and
|
||||
to be removed in the next major release. This change was needed due to the
|
||||
recently introduced `PUBSUB` command in Redis 2.8.
|
||||
|
||||
|
||||
v0.8.4 (2013-07-27)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Added `DUMP` and `RESTORE` to the server profile for Redis 2.6.
|
||||
|
||||
@@ -45,7 +105,7 @@ v0.8.4 (2013-07-27)
|
||||
|
||||
|
||||
v0.8.3 (2013-02-18)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Added `CLIENT SETNAME` and `CLIENT GETNAME` (ISSUE #102).
|
||||
|
||||
@@ -74,7 +134,7 @@ v0.8.3 (2013-02-18)
|
||||
|
||||
|
||||
v0.8.2 (2013-02-03)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Added `Predis\Session\SessionHandler` to make it easy to store PHP sessions
|
||||
on Redis using Predis. Please note that this class needs either PHP >= 5.4.0
|
||||
@@ -89,7 +149,7 @@ v0.8.2 (2013-02-03)
|
||||
|
||||
|
||||
v0.8.1 (2013-01-19)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- The `connections` client option can now accept a callable object returning
|
||||
an instance of `Predis\Connection\ConnectionFactoryInterface`.
|
||||
@@ -121,7 +181,7 @@ v0.8.1 (2013-01-19)
|
||||
|
||||
|
||||
v0.8.0 (2012-10-23)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- The default server profile for Redis is now `2.6`.
|
||||
|
||||
@@ -186,7 +246,7 @@ v0.8.0 (2012-10-23)
|
||||
|
||||
|
||||
v0.7.3 (2012-06-01)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- New commands available in the Redis v2.6 profile (dev): `BITOP`, `BITCOUNT`.
|
||||
|
||||
@@ -208,7 +268,7 @@ v0.7.3 (2012-06-01)
|
||||
|
||||
|
||||
v0.7.2 (2012-04-01)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Added `2.6` in the server profiles aliases list for the upcoming Redis 2.6.
|
||||
`2.4` is still the default server profile. `dev` now targets Redis 2.8.
|
||||
@@ -226,7 +286,7 @@ v0.7.2 (2012-04-01)
|
||||
|
||||
|
||||
v0.7.1 (2011-12-27)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- The PEAR channel on PearHub has been deprecated in favour of `pear.nrk.io`.
|
||||
|
||||
@@ -245,7 +305,7 @@ v0.7.1 (2011-12-27)
|
||||
|
||||
|
||||
v0.7.0 (2011-12-11)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Predis now adheres to the PSR-0 standard which means that there is no more a
|
||||
single file holding all the classes of the library, but multiple files (one
|
||||
@@ -319,7 +379,7 @@ v0.7.0 (2011-12-11)
|
||||
|
||||
|
||||
v0.6.6 (2011-04-01)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Switched to Redis 2.2 as the default server profile (there are no changes
|
||||
that would break compatibility with previous releases). Long command names
|
||||
@@ -358,7 +418,7 @@ v0.6.6 (2011-04-01)
|
||||
|
||||
|
||||
v0.6.5 (2011-02-12)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- __FIX__: due to an untested internal change introduced in v0.6.4, a wrong
|
||||
handling of bulk reads of zero-length values was producing protocol
|
||||
@@ -366,7 +426,7 @@ v0.6.5 (2011-02-12)
|
||||
|
||||
|
||||
v0.6.4 (2011-02-12)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Various performance improvements (15% ~ 25%) especially when dealing with
|
||||
long multibulk replies or when using clustered connections.
|
||||
@@ -380,7 +440,7 @@ v0.6.4 (2011-02-12)
|
||||
|
||||
|
||||
v0.6.3 (2011-01-01)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- New commands available in the Redis v2.2 profile (dev):
|
||||
- Strings: `SETRANGE`, `GETRANGE`, `SETBIT`, `GETBIT`
|
||||
@@ -394,7 +454,7 @@ v0.6.3 (2011-01-01)
|
||||
|
||||
|
||||
v0.6.2 (2010-11-28)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Minor internal improvements and clean ups.
|
||||
|
||||
@@ -419,7 +479,7 @@ v0.6.2 (2010-11-28)
|
||||
|
||||
|
||||
v0.6.1 (2010-07-11)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Minor internal improvements and clean ups.
|
||||
|
||||
@@ -461,7 +521,7 @@ v0.6.1 (2010-07-11)
|
||||
|
||||
|
||||
v0.6.0 (2010-05-24)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
- Switched to the new multi-bulk request protocol for all of the commands
|
||||
in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now
|
||||
@@ -576,7 +636,7 @@ v0.6.0 (2010-05-24)
|
||||
|
||||
|
||||
v0.5.1 (2010-01-23)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
|
||||
* `RPOPLPUSH` has been changed from bulk command to inline command in Redis
|
||||
1.2.1, so `ListPopLastPushHead` now extends `InlineCommand`. The old behavior
|
||||
@@ -591,5 +651,5 @@ v0.5.1 (2010-01-23)
|
||||
|
||||
|
||||
v0.5.0 (2010-01-09)
|
||||
===============================================================================
|
||||
================================================================================
|
||||
* First versioned release of Predis
|
||||
|
||||
+19
-15
@@ -1,18 +1,18 @@
|
||||
## Filing bug reports ##
|
||||
|
||||
Bugs or feature requests can be posted online on the [GitHub issues](http://github.com/nrk/predis/issues)
|
||||
Bugs or feature requests can be posted on the [GitHub issues](http://github.com/nrk/predis/issues)
|
||||
section of the project.
|
||||
|
||||
When reporting bugs, in addition to the obvious description of your issue you __must__ always provide
|
||||
some essential information about your environment such as:
|
||||
|
||||
1. version of Predis (check the `VERSION` file or the `Predis\Client::VERSION` constant).
|
||||
2. version of Redis (check the `redis_version` field returned by [`INFO`](http://redis.io/commands/info)).
|
||||
2. version of Redis (check `redis_version` returned by [`INFO`](http://redis.io/commands/info)).
|
||||
3. version of PHP.
|
||||
4. name and version of the operating system.
|
||||
5. when possible, a small snippet of code that reproduces the issue.
|
||||
|
||||
__Think about it__: we do not have a crystal ball and cannot predict things and peer into the unknown,
|
||||
__Think about it__: we do not have a crystal ball and cannot predict things or peer into the unknown
|
||||
so please provide as much details as possible to help us isolating issues and fix them.
|
||||
|
||||
__Never__ use GitHub issues to post generic questions about Predis! When you have questions about
|
||||
@@ -22,19 +22,23 @@ soon as possible.
|
||||
|
||||
## Contributing code ##
|
||||
|
||||
If you want to work on Predis, it is highly recommended that you first run the test suite in order to
|
||||
check that everything is OK, and report strange behaviours or bugs. When modifying Predis please make
|
||||
sure that no warnings or notices are emitted by PHP by running the interpreter in your development
|
||||
If you want to work on Predis, it is highly recommended that you first run the test suite in order
|
||||
to check that everything is OK and report strange behaviours or bugs. When modifying Predis please
|
||||
make sure that no warnings or notices are emitted by PHP running the interpreter in your development
|
||||
environment with the `error_reporting` variable set to `E_ALL | E_STRICT`.
|
||||
|
||||
The recommended way to contribute to Predis is to fork the project on GitHub, create new topic branches
|
||||
on your newly created repository to fix or add features (possibly with tests covering your modifications)
|
||||
and then open a new pull request with a description of the applied changes. Obviously you can use any
|
||||
other Git hosting provider of your preference.
|
||||
The recommended way to contribute to Predis is to fork the project on GitHub, create topic branches
|
||||
on your newly created repository to fix bugs or add new features (possibly with tests covering your
|
||||
modifications) and then open a pull request with a description of the applied changes. Obviously you
|
||||
can use any other Git hosting provider of your preference.
|
||||
|
||||
When writing code please follow the [basic coding (PSR-1)](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
|
||||
and [coding style (PSR-2)](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||
standards and stick with the conventions used in Predis to name classes and interfaces.
|
||||
We always aim for consistency in our code base so you should follow basic coding rules as defined by
|
||||
[PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
|
||||
and [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||
and stick with the conventions used in Predis to name classes and interfaces. Indentation should be
|
||||
done with 4 spaces and code should be wrapped at 100 columns (please try to stay within this limit
|
||||
even if the above mentioned official coding guidelines set the soft limit to 120 columns).
|
||||
|
||||
Please also follow some basic [commit guidelines](http://git-scm.com/book/ch5-2.html#Commit-Guidelines)
|
||||
before opening pull requests.
|
||||
Please follow these [commit guidelines](http://git-scm.com/book/ch5-2.html#Commit-Guidelines) when
|
||||
committing your code to Git and always write a meaningful (not necessarily extended) description of
|
||||
your changes before opening pull requests.
|
||||
|
||||
@@ -1,41 +1,39 @@
|
||||
# Some frequently asked questions about Predis #
|
||||
_________________________________________________
|
||||
|
||||
________________________________________________
|
||||
|
||||
### What is the point of Predis? ###
|
||||
|
||||
The main point of Predis is about offering a highly customizable client for Redis that can be easily
|
||||
extended by developers while still being reasonabily fast. With Predis you can swap almost any class
|
||||
used internally with your own custom implementation: you can build connection classes, or new
|
||||
distribution strategies for client-side sharding, or class handlers to replace existing commands or
|
||||
add new ones. All of this can be achieved without messing with the source code of the library and
|
||||
directly in your own application. Given the fast pace at which Redis is developed and adds new
|
||||
features, this can be a great asset that allows you to add new and still missing features or commands,
|
||||
or change the behaviour of the library without the need to break your dependencies in production code
|
||||
(well, at least to some degree).
|
||||
The main point of Predis is about offering a highly customizable and extensible client for Redis,
|
||||
that can be easily extended by developers while still being reasonabily fast. With Predis you can
|
||||
swap almost any class with your own custom implementation: you can have custom connection classes,
|
||||
new distribution strategies for client-side sharding, or handlers to replace or add Redis commands.
|
||||
All of this can be achieved without messing with the source code of the library and directly in your
|
||||
own application. Given the fast pace at which Redis is developed and adds new features, this can be
|
||||
a great asset since it allows developers to add new and still missing features or commands or change
|
||||
the standard behaviour of the library without the need to break dependencies in production code (at
|
||||
least to some degree).
|
||||
|
||||
### Does Predis support UNIX domain sockets and persistent connections? ###
|
||||
|
||||
Yes. Obviously, persistent connections actually work when using PHP configured as a persistent process that
|
||||
gets recycled between requests (see [PHP-FPM](http://php-fpm.org/)).
|
||||
|
||||
Yes. Obviously persistent connections actually work only when using PHP configured as a persistent
|
||||
process reused by the web server (see [PHP-FPM](http://php-fpm.org)).
|
||||
|
||||
### Does Predis support transparent (de)serialization of values? ###
|
||||
|
||||
No, and it will not ever do that for you by default. The reason behind this decision is that serialization
|
||||
is usually something that developers prefer to customize depending on their needs and can not be easily
|
||||
generalized when using Redis because of the many possible access patterns for the data. This does not
|
||||
mean that it is impossible to have such a feature, you can leverage Predis' extensibility to define your
|
||||
own serialization-aware commands. See [here](http://github.com/nrk/predis/issues/29#issuecomment-1202624)
|
||||
for more details on how to implement such a feature with a practical example.
|
||||
|
||||
No and it will not ever do that by default. The reason behind this decision is that serialization is
|
||||
usually something that developers prefer to customize depending on their needs and can not be easily
|
||||
generalized when using Redis because of the many possible access patterns for your data. This does
|
||||
not mean that it is impossible to have such a feature since you can leverage the extensibility of
|
||||
this library to define your own serialization-aware commands. You can find more details about how to
|
||||
do that [on this issue](http://github.com/nrk/predis/issues/29#issuecomment-1202624).
|
||||
|
||||
### How can I force Predis to connect to Redis before sending any command? ###
|
||||
|
||||
Explicitly connecting to Redis is usually not needed since the client library relies on lazily initialized
|
||||
connections to the server, but this behavior can be inconvenient in certain scenarios when you absolutely
|
||||
need to do an upfront check to detect if the server is up and running and eventually catch exceptions on
|
||||
failures. In this case developers can use `Predis\Client::connect()` to explicitly connect to the server:
|
||||
Explicitly connecting to Redis is usually not needed since the client initializes connections lazily
|
||||
only when they are needed. Admittedly, this behavior can be inconvenient in certain scenarios when
|
||||
you absolutely need to perform an upfront check to determine if the server is up and running and
|
||||
eventually catch exceptions on failures. Forcing the client to open the underlying connection can be
|
||||
done by invoking `Predis\Client::connect()`:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client();
|
||||
@@ -49,112 +47,123 @@ try {
|
||||
$client->info();
|
||||
```
|
||||
|
||||
### How Predis abstracts Redis commands? ###
|
||||
|
||||
### How Predis implements abstraction of Redis commands? ###
|
||||
|
||||
The approach used in Predis to implement the abstraction of Redis commands is quite simple. By default
|
||||
every command in the library follows exactly the same argument list as defined in the great online
|
||||
[Redis documentation](http://redis.io/commands) which makes things pretty easy if you already know how
|
||||
Redis works or if you need to look up how to use certain commands. Alternatively, variadic commands can
|
||||
accept an array for keys or values (depending on the command) instead of a list of arguments. See for
|
||||
example how [RPUSH](http://redis.io/commands/rpush) or [HMSET](http://redis.io/commands/hmset) work:
|
||||
The approach used to implement Redis commands is quite simple: by default each command follows the
|
||||
same signature as defined on the [Redis documentation](http://redis.io/commands) which makes things
|
||||
pretty easy if you already know how Redis works or you need to look up how to use certain commands.
|
||||
Alternatively, variadic commands can accept an array for keys or values (depending on the command)
|
||||
instead of a list of arguments. Commands such as [`RPUSH`](http://redis.io/commands/rpush) and
|
||||
[`HMSET`](http://redis.io/commands/hmset) are great examples:
|
||||
|
||||
```php
|
||||
$client->rpush('my:list', 'value1', 'value2', 'value3'); // values as arguments
|
||||
$client->rpush('my:list', array('value1', 'value2', 'value3')); // values as single argument array
|
||||
$client->rpush('my:list', 'value1', 'value2', 'value3'); // plain method arguments
|
||||
$client->rpush('my:list', ['value1', 'value2', 'value3']); // single argument array
|
||||
|
||||
$client->hmset('my:hash', 'field1', 'value1', 'field2', 'value2'); // values as arguments
|
||||
$client->hmset('my:hash', array('field1'=>'value1', 'field2'=>'value2'); // values as single named array
|
||||
$client->hmset('my:hash', 'field1', 'value1', 'field2', 'value2'); // plain method arguments
|
||||
$client->hmset('my:hash', ['field1'=>'value1', 'field2'=>'value2']); // single named array
|
||||
```
|
||||
|
||||
The only exception to this _rule_ is the [SORT](http://redis.io/commands/sort) command for which modifiers are
|
||||
[passed using a named array](tests/Predis/Command/KeySortTest.php#L56-77).
|
||||
An exception to this rule is [`SORT`](http://redis.io/commands/sort) for which modifiers are passed
|
||||
[using a named array](tests/Predis/Command/KeySortTest.php#L54-L75).
|
||||
|
||||
|
||||
|
||||
# Frequently asked questions about performances #
|
||||
# Speaking about performances... #
|
||||
_________________________________________________
|
||||
|
||||
|
||||
### Predis is a pure-PHP implementation: it can not be fast enough! ###
|
||||
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you
|
||||
a couple of easy numbers using a single Predis client with PHP 5.4.7 (custom build) and Redis 2.2
|
||||
(localhost) under Ubuntu 12.04.1 (running on a Intel Q6600):
|
||||
It really depends, but most of the times the answer is: _yes, it is fast enough_. I will give you a
|
||||
couple of easy numbers with a simple test that uses a single client and is executed by PHP 5.5.6
|
||||
against a local instance of Redis 2.8 that runs under Ubuntu 13.10 on a Intel Q6600:
|
||||
|
||||
21500 SET/sec using 12 bytes for both key and value
|
||||
21000 GET/sec while retrieving the very same values
|
||||
0.130 seconds to fetch 30000 keys using _KEYS *_.
|
||||
```
|
||||
21000 SET/sec using 12 bytes for both key and value.
|
||||
21000 GET/sec while retrieving the very same values.
|
||||
0.130 seconds to fetch 30000 keys using _KEYS *_.
|
||||
```
|
||||
|
||||
How does it compare with a nice C-based extension such as [__phpredis__](http://github.com/nicolasff/phpredis)?
|
||||
How does it compare with [__phpredis__](http://github.com/nicolasff/phpredis), a nice C extension
|
||||
providing an efficient client for Redis?
|
||||
|
||||
30100 SET/sec using 12 bytes for both key and value
|
||||
29400 GET/sec while retrieving the very same values
|
||||
0.035 seconds to fetch 30000 keys using "KEYS *"".
|
||||
```
|
||||
30100 SET/sec using 12 bytes for both key and value
|
||||
29400 GET/sec while retrieving the very same values
|
||||
0.035 seconds to fetch 30000 keys using "KEYS *"".
|
||||
```
|
||||
|
||||
Wow, __phpredis__ looks so much faster! Well we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected, but there is a fundamental flaw in them: is this really how you are
|
||||
going to use Redis in your application? Are you really going to send thousands of commands in a for-loop
|
||||
for each page request using a single client instance? If so, well I guess you are probably doing something
|
||||
wrong. Also, if you need to SET or GET multiple keys you should definitely use commands such as MSET and
|
||||
MGET. You can also use pipelining to get more performances when this technique can be used.
|
||||
Wow __phpredis__ seems much faster! Well, we are comparing a C extension with a pure-PHP library so
|
||||
lower numbers are quite expected but there is a fundamental flaw in them: is this really how you are
|
||||
going to use Redis in your application? Are you really going to send thousands of commands using a
|
||||
for-loop on each page request using a single client instance? If so... well I guess you are probably
|
||||
doing something wrong. Also, if you need to `SET` or `GET` multiple keys you should definitely use
|
||||
commands such as `MSET` and `MGET`. You can also use pipelining to get more performances when this
|
||||
technique can be used.
|
||||
|
||||
There is one more thing. We have tested the overhead of Predis by connecting on a localhost instance of
|
||||
Redis, but how these numbers change when we hit the network by connecting to instances of Redis that
|
||||
reside on other servers?
|
||||
There is one more thing: we have tested the overhead of Predis by connecting on a localhost instance
|
||||
of Redis but how these numbers change when we hit the physical network by connecting to remote Redis
|
||||
instances?
|
||||
|
||||
Using Predis:
|
||||
3200 SET/sec using 12 bytes for both key and value
|
||||
3200 GET/sec while retrieving the very same values
|
||||
0.132 seconds to fetch 30000 keys using "KEYS *".
|
||||
```
|
||||
Using Predis:
|
||||
3200 SET/sec using 12 bytes for both key and value
|
||||
3200 GET/sec while retrieving the very same values
|
||||
0.132 seconds to fetch 30000 keys using "KEYS *".
|
||||
|
||||
Using phpredis:
|
||||
3500 SET/sec using 12 bytes for both key and value
|
||||
3500 GET/sec while retrieving the very same values
|
||||
0.045 seconds to fetch 30000 keys using "KEYS *".
|
||||
Using phpredis:
|
||||
3500 SET/sec using 12 bytes for both key and value
|
||||
3500 GET/sec while retrieving the very same values
|
||||
0.045 seconds to fetch 30000 keys using "KEYS *".
|
||||
```
|
||||
|
||||
There you go, you get almost the same average numbers and the reason is quite simple: network latency
|
||||
is a real performance killer and you cannot do (almost) anything about that. As a disclaimer, please
|
||||
remember that we are measuring the overhead of client libraries implementations and the effects of the
|
||||
network round-trip time, we are not really measuring how fast Redis is. Redis shines the best with
|
||||
thousands of concurrent clients doing requests! Also, actual performances should be measured according
|
||||
to how your application will use Redis.
|
||||
There you go, you get almost the same average numbers and the reason is simple: network latency is a
|
||||
real performance killer and you cannot do (almost) anything about that. As a disclaimer, remember
|
||||
that we are measuring the overhead of client libraries implementations and the effects of network
|
||||
round-trip times, so we are not really measuring how fast Redis is. Redis shines best with thousands
|
||||
of concurrent clients doing requests! Also, actual performances should be measured according to how
|
||||
your application will use Redis.
|
||||
|
||||
### I am convinced, but performances for multi-bulk responses are still worse ###
|
||||
|
||||
### I am convinced, but performances for multi-bulk replies (e.g. _KEYS *_) are still worse ###
|
||||
Fair enough, but there is an option available if you need even more speed and consists on installing
|
||||
__[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name) and let the
|
||||
client use it. __phpiredis__ is another C extension that wraps __hiredis__ (the official C client
|
||||
library for Redis) with a thin layer exposing its features to PHP. You can then choose between two
|
||||
different connection classes:
|
||||
|
||||
Fair enough, but there is actually an option for you if you need even more speed and it consists on
|
||||
installing __[phpiredis](http://github.com/nrk/phpiredis)__ (note the additional _i_ in the name)
|
||||
and let Predis using it. __phpiredis__ is a C-based extension that wraps __hiredis__ (the official
|
||||
Redis C client library) with a thin layer that exposes its features to PHP. You can choose between
|
||||
two different connection backend classes: `Predis\Connection\PhpiredisConnection` (it depends on the
|
||||
`socket` extension) and `Predis\Connection\PhpiredisStreamConnection` (it uses PHP's native streams).
|
||||
You will now get the benefits of a faster protocol parser just by adding a couple of lines of code:
|
||||
- `Predis\Connection\PhpiredisStreamConnection` (using native PHP streams).
|
||||
- `Predis\Connection\PhpiredisConnection` (requires `ext-socket`).
|
||||
|
||||
You will now get the benefits of a faster protocol serializer and parser just by adding a couple of
|
||||
lines of code:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisConnection',
|
||||
),
|
||||
'tcp' => 'Predis\Connection\PhpiredisStreamConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisConnection',
|
||||
),
|
||||
));
|
||||
```
|
||||
|
||||
As simple as it is, nothing will really change in the way you use the library in your application. So,
|
||||
how fast is it now? There are not much improvements for inline or short bulk replies (e.g. _SET_ or
|
||||
_GET_), but the speed for parsing multi-bulk replies is now on par with phpredis:
|
||||
Dead simple. Nothing changes in the way you use the library in your application. So how fast is it
|
||||
our basic benchmark script now? There are not much improvements for inline or short bulk responses
|
||||
like the ones returned by `SET` and `GET`, but the speed for parsing multi-bulk responses is now on
|
||||
par with phpredis:
|
||||
|
||||
Using Predis with a phpiredis-based connection to fetch 30000 keys using _KEYS *_:
|
||||
```
|
||||
Fatching 30000 keys with _KEYS *_ using Predis paired with phpiredis::
|
||||
|
||||
0.035 seconds from a local Redis instance
|
||||
0.047 seconds from a remote Redis instance
|
||||
0.035 seconds from a local Redis instance
|
||||
0.047 seconds from a remote Redis instance
|
||||
```
|
||||
|
||||
### If I need an extension to get better performances, why not using phpredis? ###
|
||||
|
||||
### If I need to install a C extension to get better performances, why not using phpredis? ###
|
||||
|
||||
Good question. Generically speaking, if you need absolute uber-speed using localhost instances of Redis
|
||||
and you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you
|
||||
do not need any kind of extensibility or guaranteed backwards compatibility with different versions of
|
||||
Redis (Predis currently supports from 1.2 up to 2.6, and even the current development version), then
|
||||
using __phpredis__ can make sense for you. Otherwise, Predis is perfect for the job. __phpiredis__
|
||||
can give you a nice speed bump, but using it is not mandatory.
|
||||
Good question. Generically speaking if you need absolute uber-speed using Redis on the localhost and
|
||||
you do not care about abstractions built around some Redis features such as MULTI / EXEC, or if you
|
||||
do not need any kind of extensibility or guaranteed backwards compatibility with different versions
|
||||
of Redis (Predis currently supports from 1.2 up to 2.8 and the current development version), then
|
||||
using __phpredis__ makes absolutely sense. Otherwise, Predis is perfect for the job and by adding
|
||||
__phpiredis__ you can get a nice speed bump almost for free.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2013 Daniele Alessandri
|
||||
Copyright (c) 2009-2014 Daniele Alessandri
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
||||
@@ -1,166 +1,229 @@
|
||||
# Predis #
|
||||
|
||||
[](https://packagist.org/packages/predis/predis)
|
||||
[](https://packagist.org/packages/predis/predis)
|
||||
|
||||
Predis is a flexible and feature-complete PHP (>= 5.3) client library for the Redis key-value store.
|
||||
Predis is a flexible and feature-complete [Redis](http://redis.io) client library for PHP >= 5.3.
|
||||
|
||||
The library does not require any additional extension loaded in PHP but it can be optionally paired
|
||||
with the [phpiredis](https://github.com/nrk/phpiredis) C-based extension to lower the overhead of
|
||||
serializing and parsing the Redis protocol. Predis is also available in an asynchronous fashion
|
||||
through the experimental client provided by the [Predis\Async](http://github.com/nrk/predis-async)
|
||||
library.
|
||||
By default Predis does not require any additional C extension, but it can be optionally paired with
|
||||
[phpiredis](https://github.com/nrk/phpiredis) to lower the overhead of serializing and parsing the
|
||||
Redis protocol. An asynchronous implementation of the client, albeit experimental, is also available
|
||||
through [Predis\Async](https://github.com/nrk/predis-async).
|
||||
|
||||
For a list of frequently asked questions about Predis see our [FAQ](FAQ.md).
|
||||
More details are available on the [official wiki](http://wiki.github.com/nrk/predis) of the project.
|
||||
Predis can be used with [HHVM](http://www.hhvm.com) >= 2.4.0, but there are no guarantees you will
|
||||
not run into unexpected issues (especially with the JIT compiler enabled via `Eval.Jit = true`) due
|
||||
to HHVM being still under heavy development, thus unstable and not yet 100% compatible with PHP.
|
||||
|
||||
More details about the project can be found in our [frequently asked questions](FAQ.md) section or
|
||||
on the online [wiki](https://github.com/nrk/predis/wiki).
|
||||
|
||||
|
||||
## Main features ##
|
||||
|
||||
- Wide range of Redis versions supported (from __1.2__ to __2.8__ and unstable) using server profiles.
|
||||
- Wide range of Redis versions supported (from __1.2__ to __2.8__ and unstable) using profiles.
|
||||
- Clustering via client-side sharding using consistent hashing or custom distributors.
|
||||
- Smart support for [redis-cluster](http://redis.io/topics/cluster-spec) (Redis >= 3.0).
|
||||
- Client-side sharding via consistent hashing or custom distribution strategies.
|
||||
- Support for master / slave replication configurations (write on master, read from slaves).
|
||||
- Transparent key prefixing strategy capable of handling any command known that has keys in its arguments.
|
||||
- Command pipelining on single and aggregated connections.
|
||||
- Abstraction for Redis transactions (Redis >= 2.0) with support for CAS operations (Redis >= 2.2).
|
||||
- Abstraction for Lua scripting (Redis >= 2.6) capable of automatically switching between `EVAL` and `EVALSHA`.
|
||||
- Abstraction based on PHP iterators for `SCAN`, `SSCAN`, `ZSCAN` and `HSCAN` (Redis >= 2.8).
|
||||
- Connections to Redis instances are lazily established upon the first call to a command by the client.
|
||||
- Ability to connect to Redis using TCP/IP or UNIX domain sockets with support for persistent connections.
|
||||
- Ability to specify alternative connection classes to use different types of network or protocol backends.
|
||||
- Flexible system to define and register your own set of commands or server profiles to client instances.
|
||||
- Support for master-slave replication configurations (write on master, read from slaves).
|
||||
- Transparent key prefixing for all Redis commands.
|
||||
- Command pipelining (works on both single and aggregate connections).
|
||||
- Abstraction for Redis transactions (Redis >= 2.0) supporting CAS operations (Redis >= 2.2).
|
||||
- Abstraction for Lua scripting (Redis >= 2.6) with automatic switching between `EVALSHA` or `EVAL`.
|
||||
- Abstraction for `SCAN`, `SSCAN`, `ZSCAN` and `HSCAN` (Redis >= 2.8) based on PHP iterators.
|
||||
- Connections to Redis are established lazily by the client upon the first command.
|
||||
- Support for both TCP/IP and UNIX domain sockets and persistent connections.
|
||||
- Support for [Webdis](http://webd.is) (both `ext-curl` and `ext-phpiredis` are needed).
|
||||
- Support for custom connection classes for providing different network or protocol backends.
|
||||
- Flexible system for defining and registering custom sets of supported commands or profiles.
|
||||
|
||||
|
||||
## How to use Predis ##
|
||||
|
||||
Predis is available on [Packagist](http://packagist.org/packages/predis/predis) for an easy installation
|
||||
using [Composer](http://packagist.org/about-composer). Composer helps you manage dependencies for your
|
||||
projects and libraries without much hassle which makes it the preferred way to get up and running with
|
||||
new applications. Alternatively, the library is available on our [own PEAR channel](http://pear.nrk.io)
|
||||
for a more traditional installation via PEAR. Zip and tar.gz archives are also downloadable from GitHub
|
||||
by browsing the list of [tagged releases](http://github.com/nrk/predis/tags).
|
||||
Predis is available on [Packagist](http://packagist.org/packages/predis/predis) which allows a quick
|
||||
installation using [Composer](http://packagist.org/about-composer). Alternatively, the library can
|
||||
be found on our [own PEAR channel](http://pear.nrk.io) for a more traditional installation via PEAR.
|
||||
Ultimately, archives of each release are [available on GitHub](https://github.com/nrk/predis/tags).
|
||||
|
||||
|
||||
### Loading the library ###
|
||||
|
||||
Predis relies on the autoloading features of PHP to load its files when needed and complies with the
|
||||
[PSR-0 standard](http://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) which makes it
|
||||
compatible with most of the major frameworks and libraries. Autoloading in your application is handled
|
||||
automatically when managing the dependencies with Composer, but you can also leverage its own autoloader
|
||||
class if you are going to use it in a project or script without any PSR-0 compliant autoloading facility:
|
||||
[PSR-0 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) which makes
|
||||
it compatible with most PHP frameworks. Autoloading is handled automatically when dependencies are
|
||||
managed using Composer, but you can also leverage its own autoloader if you are going to use it in a
|
||||
project or script without any PSR-0 compliant autoloading facility:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// prepend a base path if Predis is not present in your "include_path".
|
||||
// Prepend a base path if Predis is not available in your "include_path".
|
||||
require 'Predis/Autoloader.php';
|
||||
|
||||
Predis\Autoloader::register();
|
||||
```
|
||||
|
||||
It is possible to create a single [Phar](http://www.php.net/manual/en/intro.phar.php) archive from the
|
||||
repository just by launching `bin/create-phar.php`. The generated Phar archive ships with a stub defining
|
||||
an autoloader function for Predis, so you just need to require the Phar to be able to use the library.
|
||||
|
||||
Alternatively it is possible to generate a single PHP file that holds every class, just like older versions
|
||||
of Predis, using `bin/create-single-file.php`. In this way you can load Predis in your scripts simply by
|
||||
using functions such as `require` and `include`, but this practice is not encouraged.
|
||||
It is possible to easily create a [phar](http://www.php.net/manual/en/intro.phar.php) archive from
|
||||
the repository just by launching `bin/create-phar`. The generated phar contains a stub defining an
|
||||
autoloader function for Predis, so you just need to require the phar to start using the library.
|
||||
Alternatively, it is also possible to generate one single PHP file that holds every class like older
|
||||
versions of Predis by launching `bin/create-single-file`, but this practice __is not__ encouraged.
|
||||
|
||||
|
||||
### Connecting to Redis ###
|
||||
|
||||
By default Predis uses `127.0.0.1` and `6379` as the default host and port when creating a new client
|
||||
instance without specifying any connection parameter:
|
||||
When not specifying any connection parameter to create a new client, Predis assumes `127.0.0.1` and
|
||||
`6379` as the default host and port and uses a connection timeout of 5 seconds:
|
||||
|
||||
```php
|
||||
$redis = new Predis\Client();
|
||||
$redis->set('foo', 'bar');
|
||||
$value = $redis->get('foo');
|
||||
$client = new Predis\Client();
|
||||
$client->set('foo', 'bar');
|
||||
$value = $client->get('foo');
|
||||
```
|
||||
|
||||
It is possible to specify the various connection parameters using URI strings or named arrays:
|
||||
Connection parameters can be supplied either in the form of URI strings or named arrays. While the
|
||||
latter is the preferred way to supply parameters, URI strings can be useful for quick configurations
|
||||
or when parameters are read from a non-structured source:
|
||||
|
||||
```php
|
||||
$redis = new Predis\Client('tcp://10.0.0.1:6379');
|
||||
|
||||
// is equivalent to:
|
||||
|
||||
$redis = new Predis\Client(array(
|
||||
// Named array of connection parameters:
|
||||
$client = new Predis\Client([
|
||||
'scheme' => 'tcp',
|
||||
'host' => '10.0.0.1',
|
||||
'port' => 6379,
|
||||
));
|
||||
]);
|
||||
|
||||
// Same set of parameters, but using an URI string:
|
||||
$client = new Predis\Client('tcp://10.0.0.1:6379');
|
||||
```
|
||||
|
||||
|
||||
### Pipelining commands to multiple instances of Redis with client-side sharding ###
|
||||
|
||||
Pipelining helps with performances when there is the need to send many commands to a server in one go.
|
||||
Furthermore, pipelining works transparently even on aggregated connections. To achieve this, Predis
|
||||
supports client-side sharding using consistent-hashing on keys while clustered connections are supported
|
||||
natively by the client class.
|
||||
When an array of connections parameters is provided, Predis automatically works in clustering mode
|
||||
using client-side sharding. Both named arrays and URI strings can be mixed for providing each node
|
||||
configuration:
|
||||
|
||||
```php
|
||||
$redis = new Predis\Client(array(
|
||||
array('host' => '10.0.0.1', 'port' => 6379),
|
||||
array('host' => '10.0.0.2', 'port' => 6379)
|
||||
));
|
||||
$client = new Predis\Client([
|
||||
'tcp://10.0.0.1?alias=first-node',
|
||||
['host' => '10.0.0.2', 'alias' => 'second-node'],
|
||||
]);
|
||||
```
|
||||
|
||||
$replies = $redis->pipeline(function ($pipe) {
|
||||
The actual list of supported connection parameters can vary depending on each connection backend so
|
||||
it is recommended to refer to their specific documentation for details.
|
||||
|
||||
|
||||
### Client configuration ###
|
||||
|
||||
Various aspects of the client can be easily configured by passing options to the second argument of
|
||||
`Predis\Client::__construct()`. Options are managed using a mini DI-alike container and their values
|
||||
are usually lazily initialized only when needed. Predis by default supports the following options:
|
||||
|
||||
- `profile`: which profile to use in order to match a specific version of Redis.
|
||||
- `prefix`: a prefix string that is automatically applied to keys found in commands.
|
||||
- `exceptions`: whether the client should throw or return responses upon Redis errors.
|
||||
- `connections`: connection backends or a connection factory to be used by the client.
|
||||
- `cluster`: which backend to use for clustering (predis, redis or custom configuration).
|
||||
- `replication`: which backend to use for replication (predis or custom configuration).
|
||||
|
||||
Users can provide custom option values, they are stored in the options container and can be accessed
|
||||
later through the library.
|
||||
|
||||
|
||||
### Aggregate connections ###
|
||||
|
||||
Predis is able to aggregate multiple connections which is the base for clustering and replication.
|
||||
By default the client implements clustering using either client-side sharding (default) or a Redis
|
||||
backed solution using [redis-cluster](http://redis.io/topics/cluster-tutorial). As for replication,
|
||||
Predis can handle single-master and multiple-slaves setups by executing read operations on slaves
|
||||
and switching to the master for write operations. The replication behaviour is fully configurable.
|
||||
|
||||
|
||||
### Command pipelines ###
|
||||
|
||||
Pipelining can help with performances when many commands need to be sent to a server by reducing the
|
||||
latency introduced by network round-trip timings. Pipelining also works with aggregate connections.
|
||||
The client can execute the pipeline inside a callable block or return a pipeline instance with the
|
||||
ability to chain commands thanks to its fluent interface:
|
||||
|
||||
```php
|
||||
// Executes a pipeline inside a given callable block:
|
||||
$responses = $client->pipeline(function ($pipe) {
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$pipe->set("key:$i", str_pad($i, 4, '0', 0));
|
||||
$pipe->get("key:$i");
|
||||
}
|
||||
});
|
||||
|
||||
// Returns a pipeline instance with fluent interface:
|
||||
$responses = $client->pipeline()->set('foo', 'bar')->get('foo')->execute();
|
||||
```
|
||||
|
||||
|
||||
### Multiple and customizable connection backends ###
|
||||
### Transactions ###
|
||||
|
||||
Predis can optionally use different connection backends to connect to Redis. Two of them leverage
|
||||
the [phpiredis](http://github.com/nrk/phpiredis) C-based extension resulting in a major speed bump
|
||||
especially when dealing with long multibulk replies, namely `Predis\Connection\PhpiredisConnection`
|
||||
(the `socket` extension is also required) and `Predis\Connection\StreamPhpiredisConnection` (it
|
||||
does not require additional extensions since it relies on PHP's native streams). Both of them can
|
||||
connect to Redis using standard TCP/IP connections or UNIX domain sockets:
|
||||
The client provides an abstraction for Redis transactions based on `MULTI` and `EXEC` with a similar
|
||||
interface to command pipelines:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array(
|
||||
'tcp' => 'Predis\Connection\PhpiredisConnection',
|
||||
'unix' => 'Predis\Connection\PhpiredisStreamConnection',
|
||||
)
|
||||
));
|
||||
// Executes a transaction inside a given callable block:
|
||||
$responses = $client->transaction(function ($tx) {
|
||||
$tx->set('foo', 'bar');
|
||||
$tx->get('foo');
|
||||
});
|
||||
|
||||
// Returns a transaction instance with fluent interface:
|
||||
$responses = $client->transaction()->set('foo', 'bar')->get('foo')->execute();
|
||||
```
|
||||
|
||||
Developers can also create their own connection backends to add support for new protocols, extend
|
||||
existing ones or provide different implementations. Connection backend classes must implement
|
||||
This abstraction can perform check-and-set operations thanks to `WATCH` and `UNWATCH` and provides
|
||||
automatic retries of transactions aborted by Redis when `WATCH`ed keys are touched. For an example
|
||||
of a transaction using CAS you can see [the following example](examples/TransactionWithCAS.php).
|
||||
|
||||
__NOTE__: the method `transaction()` is available since `v0.8.5`, older versions used `multiExec()`
|
||||
for the same purpose but it has been deprecated and will be removed in the next major release.
|
||||
|
||||
|
||||
### Customizable connection backends ###
|
||||
|
||||
Predis can use different connection backends to connect to Redis. Two of them leverage a third party
|
||||
extension such as [phpiredis](https://github.com/nrk/phpiredis) resulting in major performance gains
|
||||
especially when dealing with big multibulk responses. While one is based on PHP streams, the other
|
||||
is based on socket resources provided by `ext-socket`. Both support TCP/IP or UNIX domain sockets:
|
||||
|
||||
```php
|
||||
$client = new Predis\Client('tcp://127.0.0.1', [
|
||||
'connections' => [
|
||||
'tcp' => 'Predis\Connection\PhpiredisStreamConnection', // PHP streams
|
||||
'unix' => 'Predis\Connection\PhpiredisConnection', // ext-socket
|
||||
],
|
||||
]);
|
||||
```
|
||||
|
||||
Developers can create their own connection classes to add support for new network backends, extend
|
||||
existing ones or provide completely different implementations. Connection classes must implement
|
||||
`Predis\Connection\SingleConnectionInterface` or extend `Predis\Connection\AbstractConnection`:
|
||||
|
||||
```php
|
||||
class MyConnectionClass implements Predis\Connection\SingleConnectionInterface
|
||||
{
|
||||
// implementation goes here
|
||||
// Implementation goes here...
|
||||
}
|
||||
|
||||
// Let Predis automatically use your own class to handle connections identified by the tcp scheme.
|
||||
$client = new Predis\Client('tcp://127.0.0.1', array(
|
||||
'connections' => array('tcp' => 'MyConnectionClass')
|
||||
));
|
||||
// Use MyConnectionClass to handle connections for the `tcp` scheme:
|
||||
$client = new Predis\Client('tcp://127.0.0.1', [
|
||||
'connections' => ['tcp' => 'MyConnectionClass'],
|
||||
]);
|
||||
```
|
||||
|
||||
For a more in-depth insight on how to create new connection backends you can look at the actual
|
||||
implementation of the classes contained in the `Predis\Connection` namespace.
|
||||
For a more in-depth insight on how to create new connection backends you can refer to the actual
|
||||
implementation of the standard connection classes available in the `Predis\Connection` namespace.
|
||||
|
||||
|
||||
### Defining and registering new commands on the client at runtime ###
|
||||
### Adding support for new commands ###
|
||||
|
||||
Let's suppose Redis just added the support for a brand new feature associated with a new command. If
|
||||
you want to start using the above mentioned new feature right away without messing with Predis source
|
||||
code or waiting for it to find its way into a stable Predis release, then you can start off by creating
|
||||
a new class that matches the command type and its behaviour and then bind it to a client instance at
|
||||
runtime. Actually, it is easier done than said:
|
||||
While we try to update Predis to stay up to date with all the commands available in Redis, you might
|
||||
prefer to stick with an older version of the library or provide a different way to filter arguments
|
||||
or parse responses for specific commands. To achieve that, Predis provides the ability to implement
|
||||
new command classes to define or override commands in the server profiles used by the client:
|
||||
|
||||
```php
|
||||
// Define a new command by extending Predis\Command\AbstractCommand:
|
||||
class BrandNewRedisCommand extends Predis\Command\AbstractCommand
|
||||
{
|
||||
public function getId()
|
||||
@@ -169,22 +232,26 @@ class BrandNewRedisCommand extends Predis\Command\AbstractCommand
|
||||
}
|
||||
}
|
||||
|
||||
$redis = new Predis\Client();
|
||||
$redis->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
|
||||
$redis->newcmd();
|
||||
// Inject your command in the current profile:
|
||||
$client = new Predis\Client();
|
||||
$client->getProfile()->defineCommand('newcmd', 'BrandNewRedisCommand');
|
||||
|
||||
$response = $client->newcmd();
|
||||
```
|
||||
|
||||
|
||||
### Abstraction for handling Lua scripts as plain Redis commands ###
|
||||
### Scriptable commands ###
|
||||
|
||||
A scripted command in Predis is an abstraction for [Lua scripting](http://redis.io/commands/eval)
|
||||
with Redis >= 2.6 that allows to use a Lua script as if it was a plain Redis command registered
|
||||
in the server profile being used by the client instance. Internally, scripted commands use
|
||||
[EVALSHA](http://redis.io/commands/evalsha) to refer to a Lua script by its SHA1 hash in order
|
||||
to save bandwidth, but they are capable of falling back to [EVAL](http://redis.io/commands/eval)
|
||||
when needed:
|
||||
A scriptable command is just an abstraction for [Lua scripting](http://redis.io/commands/eval) that
|
||||
aims to simplify the usage of scripting with Redis >= 2.6. Scriptable commands can be registered in
|
||||
the server profile used by the client and are accessible as if they were plain Redis commands, but
|
||||
they define a Lua script that gets transmitted to Redis for remote execution. Internally, scriptable
|
||||
commands use by default [EVALSHA](http://redis.io/commands/evalsha) and identify a Lua script by its
|
||||
SHA1 hash to save bandwidth but [EVAL](http://redis.io/commands/eval) is automatically preferred as
|
||||
a fall back when needed:
|
||||
|
||||
```php
|
||||
// Define a new scriptable command by extending Predis\Command\ScriptedCommand:
|
||||
class ListPushRandomValue extends Predis\Command\ScriptedCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
@@ -194,8 +261,7 @@ class ListPushRandomValue extends Predis\Command\ScriptedCommand
|
||||
|
||||
public function getScript()
|
||||
{
|
||||
return
|
||||
<<<LUA
|
||||
return <<<LUA
|
||||
math.randomseed(ARGV[1])
|
||||
local rnd = tostring(math.random())
|
||||
redis.call('lpush', KEYS[1], rnd)
|
||||
@@ -204,61 +270,60 @@ LUA;
|
||||
}
|
||||
}
|
||||
|
||||
// Inject your scriptable command in the current profile:
|
||||
$client = new Predis\Client();
|
||||
$client->getProfile()->defineCommand('lpushrand', 'ListPushRandomValue');
|
||||
|
||||
$value = $client->lpushrand('random_values', $seed = mt_rand());
|
||||
$response = $client->lpushrand('random_values', $seed = mt_rand());
|
||||
```
|
||||
|
||||
|
||||
## Test suite ##
|
||||
|
||||
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running in
|
||||
production environments or containing data you are interested in!
|
||||
|
||||
Predis has a comprehensive test suite covering every aspect of the library. The suite performs integration
|
||||
tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct behaviour of the
|
||||
implementation of each command and automatically skips commands not defined in the selected version of
|
||||
Redis. If you do not have Redis up and running, integration tests can be disabled. By default, the test
|
||||
suite is configured to execute integration tests using the server profile for Redis v2.4 (which is the
|
||||
current stable version of Redis). You can optionally run the suite against a Redis instance built from
|
||||
the `unstable` branch with the development profile by changing the `REDIS_SERVER_VERSION` to `dev` in
|
||||
the `phpunit.xml` file. More details on testing Predis can be found in [the tests README](tests/README.md).
|
||||
|
||||
Predis uses Travis CI for continuous integration. You can find the results of the test suite and the build
|
||||
history [on its project page](http://travis-ci.org/nrk/predis).
|
||||
## Development ##
|
||||
|
||||
|
||||
## Dependencies ##
|
||||
### Reporting bugs and contributing code ###
|
||||
|
||||
- PHP >= 5.3.2
|
||||
- PHPUnit >= 3.5.0 (needed to run the test suite)
|
||||
Contributions to Predis are highly appreciated either in the form of pull requests for new features,
|
||||
bug fixes, or just bug reports. We only ask you to adhere to a [basic set of rules](CONTRIBUTING.md)
|
||||
before submitting your changes or filing bugs on the issue tracker to make it easier for everyone to
|
||||
stay consistent while working on the project.
|
||||
|
||||
## Links ##
|
||||
|
||||
### Project ###
|
||||
- [Source code](http://github.com/nrk/predis/)
|
||||
- [Wiki](http://wiki.github.com/nrk/predis/)
|
||||
- [Issue tracker](http://github.com/nrk/predis/issues)
|
||||
### Test suite ###
|
||||
|
||||
__ATTENTION__: Do not ever run the test suite shipped with Predis against instances of Redis running
|
||||
in production environments or containing data you are interested in!
|
||||
|
||||
Predis has a comprehensive test suite covering every aspect of the library. This test suite performs
|
||||
integration tests against a running instance of Redis (>= 2.4.0 is required) to verify the correct
|
||||
behaviour of the implementation of each command and automatically skips commands not defined in the
|
||||
specified Redis profile. If you do not have Redis up and running, integration tests can be disabled.
|
||||
By default the test suite is configured to execute integration tests using the profile for Redis 2.8
|
||||
(which is the current stable version of Redis) but can optionally target a Redis instance built from
|
||||
the `unstable` branch by modifying `phpunit.xml` and setting `REDIS_SERVER_VERSION` to `dev` so that
|
||||
the development server profile will be used. You can refer to [the tests README](tests/README.md)
|
||||
for more detailed information about testing Predis.
|
||||
|
||||
Predis uses Travis CI for continuous integration and the history for past and current builds can be
|
||||
found [on its project page](http://travis-ci.org/nrk/predis).
|
||||
|
||||
|
||||
## Other ##
|
||||
|
||||
|
||||
### Project related links ###
|
||||
|
||||
- [Source code](https://github.com/nrk/predis)
|
||||
- [Wiki](https://wiki.github.com/nrk/predis)
|
||||
- [Issue tracker](https://github.com/nrk/predis/issues)
|
||||
- [PEAR channel](http://pear.nrk.io)
|
||||
|
||||
### Related ###
|
||||
- [Redis](http://redis.io/)
|
||||
- [PHP](http://php.net/)
|
||||
- [PHPUnit](http://www.phpunit.de/)
|
||||
- [Git](http://git-scm.com/)
|
||||
|
||||
## Author ##
|
||||
### Author ###
|
||||
|
||||
- [Daniele Alessandri](mailto:suppakilla@gmail.com) ([twitter](http://twitter.com/JoL1hAHN))
|
||||
|
||||
## Contributors ##
|
||||
|
||||
- [Lorenzo Castelli](http://github.com/lcastelli)
|
||||
- [Jordi Boggiano](http://github.com/Seldaek) ([twitter](http://twitter.com/seldaek))
|
||||
- [Sebastian Waisbrot](http://github.com/seppo0010) ([twitter](http://twitter.com/seppo0010))
|
||||
for his past work on extending [phpiredis](http://github.com/nrk/phpiredis) for Predis.
|
||||
|
||||
## License ##
|
||||
### License ###
|
||||
|
||||
The code for Predis is distributed under the terms of the MIT license (see [LICENSE](LICENSE)).
|
||||
|
||||
@@ -171,13 +171,11 @@ class CommandTestCaseGenerator
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-$realm
|
||||
*/
|
||||
class $class extends CommandTestCase
|
||||
class $class extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
Executable
+221
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
// In order to be able to execute this script to create a PEAR package of Predis
|
||||
// the `pear` binary must be available and executable in your $PATH.
|
||||
// The parts used to parse author and version strings are taken from Onion (used
|
||||
// by this library in the past) just to keep on relying on the package.ini file
|
||||
// to simplify things. We might consider to switch to using the PEAR classes
|
||||
// directly in the future.
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
function executeWithBackup($file, $callback)
|
||||
{
|
||||
$exception = null;
|
||||
$backup = "$file.backup";
|
||||
|
||||
copy($file, $backup);
|
||||
|
||||
try {
|
||||
call_user_func($callback, $file);
|
||||
} catch (Exception $exception) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
unlink($file);
|
||||
rename($backup, $file);
|
||||
|
||||
if ($exception) {
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
function parseAuthor($string)
|
||||
{
|
||||
$author = array();
|
||||
|
||||
if (preg_match('/^\s*(.+?)\s*(?:"(\S+)"\s*)?<(\S+)>\s*$/x', $string , $regs)) {
|
||||
if (count($regs) == 4) {
|
||||
list($orig,$name,$user,$email) = $regs;
|
||||
$author['name'] = $name;
|
||||
$author['user'] = $user;
|
||||
$author['email'] = $email;
|
||||
} elseif (count($regs) == 3) {
|
||||
list($orig,$name,$email) = $regs;
|
||||
$author['name'] = $name;
|
||||
$author['email'] = $email;
|
||||
}
|
||||
} else {
|
||||
$author['name'] = $string;
|
||||
}
|
||||
|
||||
return $author;
|
||||
}
|
||||
|
||||
function parseVersion($string)
|
||||
{
|
||||
$version_pattern = '([0-9.]+)';
|
||||
|
||||
if (preg_match("/^\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array('min' => $regs[1] ?: '0.0.0');
|
||||
} elseif (preg_match("/^\s*[>=]+\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array('min' => $regs[1] ?: '0.0.0');
|
||||
} elseif (preg_match("/^\s*[<=]+\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array('max' => $regs[1]);
|
||||
} elseif (preg_match("/^\s*$version_pattern\s*<=>\s*$version_pattern\s*\$/x", $string, $regs)) {
|
||||
return array(
|
||||
'min' => $regs[1] ?: '0.0.0',
|
||||
'max' => $regs[2],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function addRolePath($pkg, $path, $role)
|
||||
{
|
||||
if (is_dir($path)) {
|
||||
$dirRoot = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$dirTree = new RecursiveIteratorIterator($dirRoot, RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
foreach ($dirTree as $fileinfo) {
|
||||
if ($fileinfo->isFile()) {
|
||||
addPackageFile($pkg, $fileinfo, $role, $path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach (glob($path) as $filename) {
|
||||
addPackageFile($pkg, new SplFileInfo($filename), $role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPackageFile($pkg, $fileinfo, $role, $baseDir = '')
|
||||
{
|
||||
$fileNode = $pkg->contents->dir->addChild('file');
|
||||
$fileNode->addAttribute('name', $filepath = $fileinfo->getPathname());
|
||||
$fileNode->addAttribute('role', $role);
|
||||
$fileNode->addAttribute('md5sum', md5_file($filepath));
|
||||
|
||||
$installNode = $pkg->phprelease->filelist->addChild('install');
|
||||
$installNode->addAttribute('name', $filepath);
|
||||
$installNode->addAttribute('as', !$baseDir ? basename($filepath) : substr($filepath, strlen($baseDir) + 1));
|
||||
}
|
||||
|
||||
function generatePackageXml($packageINI)
|
||||
{
|
||||
$XML = <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<package packagerversion="1.4.10" version="2.0"
|
||||
xmlns="http://pear.php.net/dtd/package-2.0"
|
||||
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
||||
http://pear.php.net/dtd/tasks-1.0.xsd
|
||||
http://pear.php.net/dtd/package-2.0
|
||||
http://pear.php.net/dtd/package-2.0.xsd" />
|
||||
XML;
|
||||
|
||||
$cfg = parse_ini_file($packageINI, true);
|
||||
$pkg = new SimpleXMLElement($XML);
|
||||
|
||||
$pkg->name = $cfg['package']['name'];
|
||||
$pkg->channel = $cfg['package']['channel'];
|
||||
$pkg->summary = $cfg['package']['desc'];
|
||||
$pkg->description = $cfg['package']['desc'];
|
||||
|
||||
$author = parseAuthor($cfg['package']['author']);
|
||||
$pkg->addChild('lead');
|
||||
$pkg->lead->name = $author['name'];
|
||||
$pkg->lead->user = $author['user'];
|
||||
$pkg->lead->email = $author['email'];
|
||||
$pkg->lead->active = 'yes';
|
||||
|
||||
$datetime = new DateTime('now');
|
||||
$pkg->date = $datetime->format('Y-m-d');
|
||||
$pkg->time = $datetime->format('H:i:s');
|
||||
|
||||
$pkg->addChild('version');
|
||||
$pkg->version->release = $cfg['package']['version'];
|
||||
$pkg->version->api = $cfg['package']['version'];
|
||||
|
||||
$pkg->addChild('stability');
|
||||
$pkg->stability->release = $cfg['package']['stability'];
|
||||
$pkg->stability->api = $cfg['package']['stability'];
|
||||
|
||||
$pkg->license = $cfg['package']['license'];
|
||||
$pkg->notes = '-';
|
||||
|
||||
$pkg->addChild('contents')->addChild('dir')->addAttribute('name', '/');
|
||||
|
||||
$pkg->addChild('dependencies')->addChild('required');
|
||||
foreach ($cfg['require'] as $required => $version) {
|
||||
$version = parseVersion($version);
|
||||
$pkg->dependencies->required->addChild($required);
|
||||
|
||||
if (isset($version['min'])) {
|
||||
$pkg->dependencies->required->$required->min = $version['min'];
|
||||
}
|
||||
if (isset($version['max'])) {
|
||||
$pkg->dependencies->required->$required->min = $version['max'];
|
||||
}
|
||||
}
|
||||
|
||||
$pkg->addChild('phprelease')->addChild('filelist');
|
||||
|
||||
$pathToRole = array(
|
||||
'doc' => 'doc', 'docs' => 'doc', 'examples' => 'doc',
|
||||
'lib' => 'php', 'src' => 'php',
|
||||
'test' => 'test', 'tests' => 'test',
|
||||
);
|
||||
|
||||
foreach (array_merge($pathToRole, $cfg['roles'] ?: array()) as $path => $role) {
|
||||
addRolePath($pkg, $path, $role);
|
||||
}
|
||||
|
||||
return $pkg;
|
||||
}
|
||||
|
||||
function savePackageXml($xml)
|
||||
{
|
||||
$dom = new DOMDocument("1.0");
|
||||
$dom->preserveWhiteSpace = false;
|
||||
$dom->formatOutput = true;
|
||||
$dom->loadXML($xml->asXML());
|
||||
|
||||
file_put_contents('package.xml', $dom->saveXML());
|
||||
}
|
||||
|
||||
function buildPackage()
|
||||
{
|
||||
passthru('pear -q package && rm package.xml');
|
||||
}
|
||||
|
||||
function modifyPhpunitXml($file)
|
||||
{
|
||||
$cfg = new SimpleXMLElement($file, null, true);
|
||||
|
||||
$cfg[0]['bootstrap'] = str_replace('tests/', '', $cfg[0]['bootstrap']);
|
||||
$cfg->testsuites->testsuite->directory = str_replace('tests/', '', $cfg->testsuites->testsuite->directory);
|
||||
|
||||
$cfg->saveXml($file);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
executeWithBackup(__DIR__.'/../phpunit.xml.dist', function ($file) {
|
||||
modifyPhpunitXml($file);
|
||||
|
||||
$pkg = generatePackageXml('package.ini');
|
||||
savePackageXml($pkg);
|
||||
|
||||
buildPackage();
|
||||
});
|
||||
@@ -321,13 +321,15 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
{
|
||||
private $use;
|
||||
private $aliases;
|
||||
private $reverseAliases;
|
||||
private $namespace;
|
||||
|
||||
public function __construct(PhpNamespace $namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->use = array();
|
||||
$this->aliases = array();
|
||||
$this->namespace = $namespace;
|
||||
$this->reverseAliases = array();
|
||||
}
|
||||
|
||||
public function add($use, $as = null)
|
||||
@@ -336,8 +338,35 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
return;
|
||||
}
|
||||
|
||||
$rename = null;
|
||||
$this->use[] = $use;
|
||||
$this->aliases[$as ?: PhpClass::extractName($use)] = $use;
|
||||
$aliasedClassName = $as ?: PhpClass::extractName($use);
|
||||
|
||||
if (isset($this->aliases[$aliasedClassName])) {
|
||||
$parentNs = $this->getParentNamespace();
|
||||
|
||||
if ($parentNs && false !== $pos = strrpos($parentNs, '\\')) {
|
||||
$parentNs = substr($parentNs, $pos);
|
||||
}
|
||||
|
||||
$newAlias = "{$parentNs}_{$aliasedClassName}";
|
||||
$rename = (object) array(
|
||||
'namespace' => $this->namespace,
|
||||
'from' => $aliasedClassName,
|
||||
'to' => $newAlias,
|
||||
);
|
||||
|
||||
$this->aliases[$newAlias] = $use;
|
||||
$as = $newAlias;
|
||||
} else {
|
||||
$this->aliases[$aliasedClassName] = $use;
|
||||
}
|
||||
|
||||
if ($as !== null) {
|
||||
$this->reverseAliases[$use] = $as;
|
||||
}
|
||||
|
||||
return $rename;
|
||||
}
|
||||
|
||||
public function getList()
|
||||
@@ -352,8 +381,14 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
|
||||
public function getPhpCode()
|
||||
{
|
||||
$reducer = function ($str, $use) {
|
||||
return $str .= "use $use;\n";
|
||||
$reverseAliases = $this->reverseAliases;
|
||||
|
||||
$reducer = function ($str, $use) use ($reverseAliases) {
|
||||
if (isset($reverseAliases[$use])) {
|
||||
return $str .= "use $use as {$reverseAliases[$use]};\n";
|
||||
} else {
|
||||
return $str .= "use $use;\n";
|
||||
}
|
||||
};
|
||||
|
||||
return array_reduce($this->getList(), $reducer, '');
|
||||
@@ -364,6 +399,15 @@ class PhpUseDirectives implements Countable, IteratorAggregate
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
public function getParentNamespace()
|
||||
{
|
||||
if (false !== $pos = strrpos($this->namespace, '\\')) {
|
||||
return substr($this->namespace, 0, $pos);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getFQN($className)
|
||||
{
|
||||
if (($nsSepFirst = strpos($className, '\\')) === false) {
|
||||
@@ -430,10 +474,19 @@ LICENSE;
|
||||
|
||||
private function extractData()
|
||||
{
|
||||
$renames = array();
|
||||
$useDirectives = $this->getNamespace()->getUseDirectives();
|
||||
|
||||
$useExtractor = function ($m) use ($useDirectives) {
|
||||
$useDirectives->add(($namespacedPath = $m[1]));
|
||||
$useExtractor = function ($m) use ($useDirectives, &$renames) {
|
||||
array_shift($m);
|
||||
|
||||
if (isset($m[1])) {
|
||||
$m[1] = str_replace(" as ", '', $m[1]);
|
||||
}
|
||||
|
||||
if ($rename = call_user_func_array(array($useDirectives, 'add'), $m)) {
|
||||
$renames[] = $rename;
|
||||
}
|
||||
};
|
||||
|
||||
$classBuffer = stream_get_contents(fopen($this->getFile()->getPathname(), 'r'));
|
||||
@@ -445,6 +498,10 @@ LICENSE;
|
||||
$classBuffer = preg_replace('/namespace\s+[\w\d_\\\\]+;\s?/', '', $classBuffer);
|
||||
$classBuffer = preg_replace_callback('/use\s+([\w\d_\\\\]+)(\s+as\s+.*)?;\s?\n?/', $useExtractor, $classBuffer);
|
||||
|
||||
foreach ($renames as $rename) {
|
||||
$classBuffer = str_replace($rename->from, $rename->to, $classBuffer);
|
||||
}
|
||||
|
||||
$this->body = trim($classBuffer);
|
||||
|
||||
$this->extractHierarchy();
|
||||
@@ -15,6 +15,9 @@
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol",
|
||||
"ext-curl": "Allows access to Webdis when paired with phpiredis"
|
||||
|
||||
@@ -33,7 +33,7 @@ function zpop($client, $key)
|
||||
// which the client bails out with an exception.
|
||||
);
|
||||
|
||||
$client->multiExec($options, function ($tx) use ($key, &$element) {
|
||||
$client->transaction($options, function ($tx) use ($key, &$element) {
|
||||
@list($element) = $tx->zrange($key, 0, 0);
|
||||
|
||||
if (isset($element)) {
|
||||
@@ -36,7 +36,7 @@ class Autoloader
|
||||
/**
|
||||
* Registers the autoloader class with the PHP SPL autoloader.
|
||||
*
|
||||
* @param boolean $prepend Prepend the autoloader on the stack instead of appending it.
|
||||
* @param bool $prepend Prepend the autoloader on the stack instead of appending it.
|
||||
*/
|
||||
public static function register($prepend = false)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ interface BasicClientInterface
|
||||
/**
|
||||
* Executes the specified Redis command.
|
||||
*
|
||||
* @param CommandInterface $command A Redis command.
|
||||
* @param CommandInterface $command A Redis command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function executeCommand(CommandInterface $command);
|
||||
|
||||
+55
-43
@@ -20,7 +20,6 @@ use Predis\Monitor\MonitorContext;
|
||||
use Predis\Option\ClientOptions;
|
||||
use Predis\Option\ClientOptionsInterface;
|
||||
use Predis\Pipeline\PipelineContext;
|
||||
use Predis\Profile\ServerProfile;
|
||||
use Predis\PubSub\PubSubContext;
|
||||
use Predis\Transaction\MultiExecContext;
|
||||
|
||||
@@ -31,7 +30,7 @@ use Predis\Transaction\MultiExecContext;
|
||||
*/
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
const VERSION = '0.8.5-dev';
|
||||
const VERSION = '0.8.6';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
@@ -41,7 +40,7 @@ class Client implements ClientInterface
|
||||
* Initializes a new client with optional connection parameters and client options.
|
||||
*
|
||||
* @param mixed $parameters Connection parameters for one or multiple servers.
|
||||
* @param mixed $options Options that specify certain behaviours for the client.
|
||||
* @param mixed $options Options that specify certain behaviours for the client.
|
||||
*/
|
||||
public function __construct($parameters = null, $options = null)
|
||||
{
|
||||
@@ -55,7 +54,7 @@ class Client implements ClientInterface
|
||||
* arguments (string, array, Predis\Profile\ServerProfile) or returns the
|
||||
* passed object if it is an instance of Predis\Option\ClientOptions.
|
||||
*
|
||||
* @param mixed $options Client options.
|
||||
* @param mixed $options Client options.
|
||||
* @return ClientOptions
|
||||
*/
|
||||
protected function filterOptions($options)
|
||||
@@ -80,7 +79,7 @@ class Client implements ClientInterface
|
||||
* types of arguments (string, array) or returns the passed object if it
|
||||
* implements Predis\Connection\ConnectionInterface.
|
||||
*
|
||||
* @param mixed $parameters Connection parameters or instance.
|
||||
* @param mixed $parameters Connection parameters or instance.
|
||||
* @return ConnectionInterface
|
||||
*/
|
||||
protected function initializeConnection($parameters)
|
||||
@@ -143,6 +142,7 @@ class Client implements ClientInterface
|
||||
* client is connected to a cluster. The new instance will use the same
|
||||
* options of the original client.
|
||||
*
|
||||
* @param string $connectionID Identifier for the connection.
|
||||
* @return Client
|
||||
*/
|
||||
public function getClientFor($connectionID)
|
||||
@@ -183,8 +183,8 @@ class Client implements ClientInterface
|
||||
/**
|
||||
* Checks if the underlying connection is connected to Redis.
|
||||
*
|
||||
* @return Boolean True means that the connection is open.
|
||||
* False means that the connection is closed.
|
||||
* @return bool True means that the connection is open.
|
||||
* False means that the connection is closed.
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
@@ -202,7 +202,7 @@ class Client implements ClientInterface
|
||||
/**
|
||||
* Retrieves a single connection out of an aggregated connections instance.
|
||||
*
|
||||
* @param string $connectionId Index or alias of the connection.
|
||||
* @param string $connectionId Index or alias of the single connection.
|
||||
* @return Connection\SingleConnectionInterface
|
||||
*/
|
||||
public function getConnectionById($connectionId)
|
||||
@@ -215,34 +215,27 @@ class Client implements ClientInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically invokes a Redis command with the specified arguments.
|
||||
* Creates a Redis command with the specified arguments and sends a request
|
||||
* to the server.
|
||||
*
|
||||
* @param string $method The name of a Redis command.
|
||||
* @param array $arguments The arguments for the command.
|
||||
* @param string $commandID Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
public function __call($commandID, $arguments)
|
||||
{
|
||||
$command = $this->profile->createCommand($method, $arguments);
|
||||
$response = $this->connection->executeCommand($command);
|
||||
$command = $this->createCommand($commandID, $arguments);
|
||||
$response = $this->executeCommand($command);
|
||||
|
||||
if ($response instanceof ResponseObjectInterface) {
|
||||
if ($response instanceof ResponseErrorInterface) {
|
||||
$response = $this->onResponseError($command, $response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $command->parseResponse($response);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createCommand($method, $arguments = array())
|
||||
public function createCommand($commandID, $arguments = array())
|
||||
{
|
||||
return $this->profile->createCommand($method, $arguments);
|
||||
return $this->profile->createCommand($commandID, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,8 +259,8 @@ class Client implements ClientInterface
|
||||
/**
|
||||
* Handles -ERR responses returned by Redis.
|
||||
*
|
||||
* @param CommandInterface $command The command that generated the error.
|
||||
* @param ResponseErrorInterface $response The error response instance.
|
||||
* @param CommandInterface $command The command that generated the error.
|
||||
* @param ResponseErrorInterface $response The error response instance.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function onResponseError(CommandInterface $command, ResponseErrorInterface $response)
|
||||
@@ -297,8 +290,8 @@ class Client implements ClientInterface
|
||||
*
|
||||
* TODO: Invert $argv and $initializer.
|
||||
*
|
||||
* @param array $argv Arguments for the initializer.
|
||||
* @param string $initializer The initializer method.
|
||||
* @param array $argv Arguments for the initializer.
|
||||
* @param string $initializer The initializer method.
|
||||
* @return mixed
|
||||
*/
|
||||
private function sharedInitializer($argv, $initializer)
|
||||
@@ -309,10 +302,12 @@ class Client implements ClientInterface
|
||||
|
||||
case 1:
|
||||
list($arg0) = $argv;
|
||||
|
||||
return is_array($arg0) ? $this->$initializer($arg0) : $this->$initializer(null, $arg0);
|
||||
|
||||
case 2:
|
||||
list($arg0, $arg1) = $argv;
|
||||
|
||||
return $this->$initializer($arg0, $arg1);
|
||||
|
||||
default:
|
||||
@@ -324,7 +319,7 @@ class Client implements ClientInterface
|
||||
* Creates a new pipeline context and returns it, or returns the results of
|
||||
* a pipeline executed inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @param mixed ... Options for the context, a callable object, or both.
|
||||
* @return PipelineContext|array
|
||||
*/
|
||||
public function pipeline(/* arguments */)
|
||||
@@ -335,8 +330,8 @@ class Client implements ClientInterface
|
||||
/**
|
||||
* Pipeline context initializer.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return PipelineContext|array
|
||||
*/
|
||||
protected function initPipeline(Array $options = null, $callable = null)
|
||||
@@ -356,8 +351,8 @@ class Client implements ClientInterface
|
||||
/**
|
||||
* Executes a pipeline context when a callable object is passed.
|
||||
*
|
||||
* @param array $options Options of the context initialization.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @param PipelineContext $pipeline Pipeline context instance.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return PipelineContext|array
|
||||
*/
|
||||
private function pipelineExecute(PipelineContext $pipeline, $callable)
|
||||
@@ -369,7 +364,11 @@ class Client implements ClientInterface
|
||||
* Creates a new transaction context and returns it, or returns the results of
|
||||
* a transaction executed inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @deprecated You should start using the new Client::transaction() method
|
||||
* as it will replace Client::multiExec() in the next major
|
||||
* version of the library.
|
||||
*
|
||||
* @param mixed ... Options for the context, a callable object, or both.
|
||||
* @return MultiExecContext|array
|
||||
*/
|
||||
public function multiExec(/* arguments */)
|
||||
@@ -377,16 +376,29 @@ class Client implements ClientInterface
|
||||
return $this->sharedInitializer(func_get_args(), 'initMultiExec');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new transaction context and returns it, or returns the results of
|
||||
* a transaction executed inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed ... Options for the context, a callable object, or both.
|
||||
* @return MultiExecContext|array
|
||||
*/
|
||||
public function transaction(/* arguments */)
|
||||
{
|
||||
return $this->sharedInitializer(func_get_args(), 'initMultiExec');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction context initializer.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return MultiExecContext|array
|
||||
*/
|
||||
protected function initMultiExec(Array $options = null, $callable = null)
|
||||
{
|
||||
$transaction = new MultiExecContext($this, $options ?: array());
|
||||
|
||||
return isset($callable) ? $transaction->execute($callable) : $transaction;
|
||||
}
|
||||
|
||||
@@ -399,8 +411,8 @@ class Client implements ClientInterface
|
||||
* Client::pubSubLoop() to create Predis\PubSub\PubSubContext
|
||||
* instances from now on.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @return PubSubExecContext|array
|
||||
* @param mixed ... Options for the context, a callable object, or both.
|
||||
* @return PubSubContext|array
|
||||
*/
|
||||
public function pubSub(/* arguments */)
|
||||
{
|
||||
@@ -411,8 +423,8 @@ class Client implements ClientInterface
|
||||
* Creates a new Publish / Subscribe context and returns it, or executes it
|
||||
* inside the optionally provided callable object.
|
||||
*
|
||||
* @param mixed $arg,... Options for the context, a callable object, or both.
|
||||
* @return PubSubExecContext|array
|
||||
* @param mixed ... Options for the context, a callable object, or both.
|
||||
* @return PubSubContext|array
|
||||
*/
|
||||
public function pubSubLoop(/* arguments */)
|
||||
{
|
||||
@@ -422,8 +434,8 @@ class Client implements ClientInterface
|
||||
/**
|
||||
* Publish / Subscribe context initializer.
|
||||
*
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @param array $options Options for the context.
|
||||
* @param mixed $callable Optional callable object used to execute the context.
|
||||
* @return PubSubContext
|
||||
*/
|
||||
protected function initPubSub(Array $options = null, $callable = null)
|
||||
|
||||
@@ -58,8 +58,8 @@ interface ClientInterface extends BasicClientInterface
|
||||
/**
|
||||
* Creates a new instance of the specified Redis command.
|
||||
*
|
||||
* @param string $method The name of a Redis command.
|
||||
* @param array $arguments The arguments for the command.
|
||||
* @param string $method The name of a Redis command.
|
||||
* @param array $arguments The arguments for the command.
|
||||
* @return Command\CommandInterface
|
||||
*/
|
||||
public function createCommand($method, $arguments = array());
|
||||
|
||||
@@ -27,7 +27,7 @@ interface CommandHashStrategyInterface
|
||||
* Returns the hash for the given command using the specified algorithm, or null
|
||||
* if the command cannot be hashed.
|
||||
*
|
||||
* @param CommandInterface $command Command to be hashed.
|
||||
* @param CommandInterface $command Command to be hashed.
|
||||
* @return int
|
||||
*/
|
||||
public function getHash(CommandInterface $command);
|
||||
@@ -35,7 +35,7 @@ interface CommandHashStrategyInterface
|
||||
/**
|
||||
* Returns the hash for the given key using the specified algorithm.
|
||||
*
|
||||
* @param string $key Key to be hashed.
|
||||
* @param string $key Key to be hashed.
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyHash($key);
|
||||
|
||||
@@ -24,8 +24,8 @@ interface DistributionStrategyInterface
|
||||
/**
|
||||
* Adds a node to the distributor with an optional weight.
|
||||
*
|
||||
* @param mixed $node Node object.
|
||||
* @param int $weight Weight for the node.
|
||||
* @param mixed $node Node object.
|
||||
* @param int $weight Weight for the node.
|
||||
*/
|
||||
public function add($node, $weight = null);
|
||||
|
||||
@@ -39,6 +39,7 @@ interface DistributionStrategyInterface
|
||||
/**
|
||||
* Gets a node from the distributor using the computed hash of a key.
|
||||
*
|
||||
* @param mixed $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key);
|
||||
|
||||
@@ -34,7 +34,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
private $nodes = array();
|
||||
|
||||
/**
|
||||
* @param int $replicas Number of replicas in the ring.
|
||||
* @param int $replicas Number of replicas in the ring.
|
||||
* @param mixed $nodeHashCallback Callback returning the string used to calculate the hash of a node.
|
||||
*/
|
||||
public function __construct($replicas = self::DEFAULT_REPLICAS, $nodeHashCallback = null)
|
||||
@@ -46,8 +46,8 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
/**
|
||||
* Adds a node to the ring with an optional weight.
|
||||
*
|
||||
* @param mixed $node Node object.
|
||||
* @param int $weight Weight for the node.
|
||||
* @param mixed $node Node object.
|
||||
* @param int $weight Weight for the node.
|
||||
*/
|
||||
public function add($node, $weight = null)
|
||||
{
|
||||
@@ -90,7 +90,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
/**
|
||||
* Returns the initialization status of the distributor.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
private function isInitialized()
|
||||
{
|
||||
@@ -143,10 +143,10 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
/**
|
||||
* Implements the logic needed to add a node to the hashring.
|
||||
*
|
||||
* @param array $ring Source hashring.
|
||||
* @param mixed $node Node object to be added.
|
||||
* @param int $totalNodes Total number of nodes.
|
||||
* @param int $replicas Number of replicas in the ring.
|
||||
* @param array $ring Source hashring.
|
||||
* @param mixed $node Node object to be added.
|
||||
* @param int $totalNodes Total number of nodes.
|
||||
* @param int $replicas Number of replicas in the ring.
|
||||
* @param float $weightRatio Weight ratio for the node.
|
||||
*/
|
||||
protected function addNodeToRing(&$ring, $node, $totalNodes, $replicas, $weightRatio)
|
||||
@@ -176,7 +176,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
/**
|
||||
* Calculates the hash for the specified value.
|
||||
*
|
||||
* @param string $value Input value.
|
||||
* @param string $value Input value.
|
||||
* @return int
|
||||
*/
|
||||
public function hash($value)
|
||||
@@ -195,7 +195,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
/**
|
||||
* Calculates the corrisponding key of a node distributed in the hashring.
|
||||
*
|
||||
* @param int $key Computed hash of a key.
|
||||
* @param int $key Computed hash of a key.
|
||||
* @return int
|
||||
*/
|
||||
private function getNodeKey($key)
|
||||
@@ -211,7 +211,7 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
|
||||
if ($item > $key) {
|
||||
$upper = $index - 1;
|
||||
} else if ($item < $key) {
|
||||
} elseif ($item < $key) {
|
||||
$lower = $index + 1;
|
||||
} else {
|
||||
return $item;
|
||||
@@ -224,9 +224,9 @@ class HashRing implements DistributionStrategyInterface, HashGeneratorInterface
|
||||
/**
|
||||
* Implements a strategy to deal with wrap-around errors during binary searches.
|
||||
*
|
||||
* @param int $upper
|
||||
* @param int $lower
|
||||
* @param int $ringKeysCount
|
||||
* @param int $upper
|
||||
* @param int $lower
|
||||
* @param int $ringKeysCount
|
||||
* @return int
|
||||
*/
|
||||
protected function wrapAroundStrategy($upper, $lower, $ringKeysCount)
|
||||
|
||||
@@ -55,6 +55,7 @@ class KetamaPureRing extends HashRing
|
||||
public function hash($value)
|
||||
{
|
||||
$hash = unpack('V', md5($value, true));
|
||||
|
||||
return $hash[1];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ interface HashGeneratorInterface
|
||||
/**
|
||||
* Generates an hash that is used by the distributor algorithm
|
||||
*
|
||||
* @param string $value Value used to generate the hash.
|
||||
* @param string $value Value used to generate the hash.
|
||||
* @return int
|
||||
*/
|
||||
public function hash($value);
|
||||
|
||||
@@ -42,117 +42,126 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function getDefaultCommands()
|
||||
{
|
||||
$keyIsFirstArgument = array($this, 'getKeyFromFirstArgument');
|
||||
$keysAreAllArguments = array($this, 'getKeyFromAllArguments');
|
||||
$getKeyFromFirstArgument = array($this, 'getKeyFromFirstArgument');
|
||||
$getKeyFromAllArguments = array($this, 'getKeyFromAllArguments');
|
||||
|
||||
return array(
|
||||
/* commands operating on the key space */
|
||||
'EXISTS' => $keyIsFirstArgument,
|
||||
'DEL' => $keysAreAllArguments,
|
||||
'TYPE' => $keyIsFirstArgument,
|
||||
'EXPIRE' => $keyIsFirstArgument,
|
||||
'EXPIREAT' => $keyIsFirstArgument,
|
||||
'PERSIST' => $keyIsFirstArgument,
|
||||
'PEXPIRE' => $keyIsFirstArgument,
|
||||
'PEXPIREAT' => $keyIsFirstArgument,
|
||||
'TTL' => $keyIsFirstArgument,
|
||||
'PTTL' => $keyIsFirstArgument,
|
||||
'SORT' => $keyIsFirstArgument, // TODO
|
||||
'DUMP' => $keyIsFirstArgument,
|
||||
'RESTORE' => $keyIsFirstArgument,
|
||||
'EXISTS' => $getKeyFromFirstArgument,
|
||||
'DEL' => $getKeyFromAllArguments,
|
||||
'TYPE' => $getKeyFromFirstArgument,
|
||||
'EXPIRE' => $getKeyFromFirstArgument,
|
||||
'EXPIREAT' => $getKeyFromFirstArgument,
|
||||
'PERSIST' => $getKeyFromFirstArgument,
|
||||
'PEXPIRE' => $getKeyFromFirstArgument,
|
||||
'PEXPIREAT' => $getKeyFromFirstArgument,
|
||||
'TTL' => $getKeyFromFirstArgument,
|
||||
'PTTL' => $getKeyFromFirstArgument,
|
||||
'SORT' => $getKeyFromFirstArgument, // TODO
|
||||
'DUMP' => $getKeyFromFirstArgument,
|
||||
'RESTORE' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on string values */
|
||||
'APPEND' => $keyIsFirstArgument,
|
||||
'DECR' => $keyIsFirstArgument,
|
||||
'DECRBY' => $keyIsFirstArgument,
|
||||
'GET' => $keyIsFirstArgument,
|
||||
'GETBIT' => $keyIsFirstArgument,
|
||||
'MGET' => $keysAreAllArguments,
|
||||
'SET' => $keyIsFirstArgument,
|
||||
'GETRANGE' => $keyIsFirstArgument,
|
||||
'GETSET' => $keyIsFirstArgument,
|
||||
'INCR' => $keyIsFirstArgument,
|
||||
'INCRBY' => $keyIsFirstArgument,
|
||||
'SETBIT' => $keyIsFirstArgument,
|
||||
'SETEX' => $keyIsFirstArgument,
|
||||
'APPEND' => $getKeyFromFirstArgument,
|
||||
'DECR' => $getKeyFromFirstArgument,
|
||||
'DECRBY' => $getKeyFromFirstArgument,
|
||||
'GET' => $getKeyFromFirstArgument,
|
||||
'GETBIT' => $getKeyFromFirstArgument,
|
||||
'MGET' => $getKeyFromAllArguments,
|
||||
'SET' => $getKeyFromFirstArgument,
|
||||
'GETRANGE' => $getKeyFromFirstArgument,
|
||||
'GETSET' => $getKeyFromFirstArgument,
|
||||
'INCR' => $getKeyFromFirstArgument,
|
||||
'INCRBY' => $getKeyFromFirstArgument,
|
||||
'INCRBYFLOAT' => $getKeyFromFirstArgument,
|
||||
'SETBIT' => $getKeyFromFirstArgument,
|
||||
'SETEX' => $getKeyFromFirstArgument,
|
||||
'MSET' => array($this, 'getKeyFromInterleavedArguments'),
|
||||
'MSETNX' => array($this, 'getKeyFromInterleavedArguments'),
|
||||
'SETNX' => $keyIsFirstArgument,
|
||||
'SETRANGE' => $keyIsFirstArgument,
|
||||
'STRLEN' => $keyIsFirstArgument,
|
||||
'SUBSTR' => $keyIsFirstArgument,
|
||||
'SETNX' => $getKeyFromFirstArgument,
|
||||
'SETRANGE' => $getKeyFromFirstArgument,
|
||||
'STRLEN' => $getKeyFromFirstArgument,
|
||||
'SUBSTR' => $getKeyFromFirstArgument,
|
||||
'BITOP' => array($this, 'getKeyFromBitOp'),
|
||||
'BITCOUNT' => $keyIsFirstArgument,
|
||||
'BITCOUNT' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on lists */
|
||||
'LINSERT' => $keyIsFirstArgument,
|
||||
'LINDEX' => $keyIsFirstArgument,
|
||||
'LLEN' => $keyIsFirstArgument,
|
||||
'LPOP' => $keyIsFirstArgument,
|
||||
'RPOP' => $keyIsFirstArgument,
|
||||
'RPOPLPUSH' => $keysAreAllArguments,
|
||||
'LINSERT' => $getKeyFromFirstArgument,
|
||||
'LINDEX' => $getKeyFromFirstArgument,
|
||||
'LLEN' => $getKeyFromFirstArgument,
|
||||
'LPOP' => $getKeyFromFirstArgument,
|
||||
'RPOP' => $getKeyFromFirstArgument,
|
||||
'RPOPLPUSH' => $getKeyFromAllArguments,
|
||||
'BLPOP' => array($this, 'getKeyFromBlockingListCommands'),
|
||||
'BRPOP' => array($this, 'getKeyFromBlockingListCommands'),
|
||||
'BRPOPLPUSH' => array($this, 'getKeyFromBlockingListCommands'),
|
||||
'LPUSH' => $keyIsFirstArgument,
|
||||
'LPUSHX' => $keyIsFirstArgument,
|
||||
'RPUSH' => $keyIsFirstArgument,
|
||||
'RPUSHX' => $keyIsFirstArgument,
|
||||
'LRANGE' => $keyIsFirstArgument,
|
||||
'LREM' => $keyIsFirstArgument,
|
||||
'LSET' => $keyIsFirstArgument,
|
||||
'LTRIM' => $keyIsFirstArgument,
|
||||
'LPUSH' => $getKeyFromFirstArgument,
|
||||
'LPUSHX' => $getKeyFromFirstArgument,
|
||||
'RPUSH' => $getKeyFromFirstArgument,
|
||||
'RPUSHX' => $getKeyFromFirstArgument,
|
||||
'LRANGE' => $getKeyFromFirstArgument,
|
||||
'LREM' => $getKeyFromFirstArgument,
|
||||
'LSET' => $getKeyFromFirstArgument,
|
||||
'LTRIM' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on sets */
|
||||
'SADD' => $keyIsFirstArgument,
|
||||
'SCARD' => $keyIsFirstArgument,
|
||||
'SDIFF' => $keysAreAllArguments,
|
||||
'SDIFFSTORE' => $keysAreAllArguments,
|
||||
'SINTER' => $keysAreAllArguments,
|
||||
'SINTERSTORE' => $keysAreAllArguments,
|
||||
'SUNION' => $keysAreAllArguments,
|
||||
'SUNIONSTORE' => $keysAreAllArguments,
|
||||
'SISMEMBER' => $keyIsFirstArgument,
|
||||
'SMEMBERS' => $keyIsFirstArgument,
|
||||
'SSCAN' => $keyIsFirstArgument,
|
||||
'SPOP' => $keyIsFirstArgument,
|
||||
'SRANDMEMBER' => $keyIsFirstArgument,
|
||||
'SREM' => $keyIsFirstArgument,
|
||||
'SADD' => $getKeyFromFirstArgument,
|
||||
'SCARD' => $getKeyFromFirstArgument,
|
||||
'SDIFF' => $getKeyFromAllArguments,
|
||||
'SDIFFSTORE' => $getKeyFromAllArguments,
|
||||
'SINTER' => $getKeyFromAllArguments,
|
||||
'SINTERSTORE' => $getKeyFromAllArguments,
|
||||
'SUNION' => $getKeyFromAllArguments,
|
||||
'SUNIONSTORE' => $getKeyFromAllArguments,
|
||||
'SISMEMBER' => $getKeyFromFirstArgument,
|
||||
'SMEMBERS' => $getKeyFromFirstArgument,
|
||||
'SSCAN' => $getKeyFromFirstArgument,
|
||||
'SPOP' => $getKeyFromFirstArgument,
|
||||
'SRANDMEMBER' => $getKeyFromFirstArgument,
|
||||
'SREM' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'ZADD' => $keyIsFirstArgument,
|
||||
'ZCARD' => $keyIsFirstArgument,
|
||||
'ZCOUNT' => $keyIsFirstArgument,
|
||||
'ZINCRBY' => $keyIsFirstArgument,
|
||||
'ZADD' => $getKeyFromFirstArgument,
|
||||
'ZCARD' => $getKeyFromFirstArgument,
|
||||
'ZCOUNT' => $getKeyFromFirstArgument,
|
||||
'ZINCRBY' => $getKeyFromFirstArgument,
|
||||
'ZINTERSTORE' => array($this, 'getKeyFromZsetAggregationCommands'),
|
||||
'ZRANGE' => $keyIsFirstArgument,
|
||||
'ZRANGEBYSCORE' => $keyIsFirstArgument,
|
||||
'ZRANK' => $keyIsFirstArgument,
|
||||
'ZREM' => $keyIsFirstArgument,
|
||||
'ZREMRANGEBYRANK' => $keyIsFirstArgument,
|
||||
'ZREMRANGEBYSCORE' => $keyIsFirstArgument,
|
||||
'ZREVRANGE' => $keyIsFirstArgument,
|
||||
'ZREVRANGEBYSCORE' => $keyIsFirstArgument,
|
||||
'ZREVRANK' => $keyIsFirstArgument,
|
||||
'ZSCORE' => $keyIsFirstArgument,
|
||||
'ZRANGE' => $getKeyFromFirstArgument,
|
||||
'ZRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZRANK' => $getKeyFromFirstArgument,
|
||||
'ZREM' => $getKeyFromFirstArgument,
|
||||
'ZREMRANGEBYRANK' => $getKeyFromFirstArgument,
|
||||
'ZREMRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANGE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANK' => $getKeyFromFirstArgument,
|
||||
'ZSCORE' => $getKeyFromFirstArgument,
|
||||
'ZUNIONSTORE' => array($this, 'getKeyFromZsetAggregationCommands'),
|
||||
'ZSCAN' => $keyIsFirstArgument,
|
||||
'ZSCAN' => $getKeyFromFirstArgument,
|
||||
'ZLEXCOUNT' => $getKeyFromFirstArgument,
|
||||
'ZRANGEBYLEX' => $getKeyFromFirstArgument,
|
||||
'ZREMRANGEBYLEX' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on hashes */
|
||||
'HDEL' => $keyIsFirstArgument,
|
||||
'HEXISTS' => $keyIsFirstArgument,
|
||||
'HGET' => $keyIsFirstArgument,
|
||||
'HGETALL' => $keyIsFirstArgument,
|
||||
'HMGET' => $keyIsFirstArgument,
|
||||
'HMSET' => $keyIsFirstArgument,
|
||||
'HINCRBY' => $keyIsFirstArgument,
|
||||
'HINCRBYFLOAT' => $keyIsFirstArgument,
|
||||
'HKEYS' => $keyIsFirstArgument,
|
||||
'HLEN' => $keyIsFirstArgument,
|
||||
'HSET' => $keyIsFirstArgument,
|
||||
'HSETNX' => $keyIsFirstArgument,
|
||||
'HVALS' => $keyIsFirstArgument,
|
||||
'HSCAN' => $keyIsFirstArgument,
|
||||
'HDEL' => $getKeyFromFirstArgument,
|
||||
'HEXISTS' => $getKeyFromFirstArgument,
|
||||
'HGET' => $getKeyFromFirstArgument,
|
||||
'HGETALL' => $getKeyFromFirstArgument,
|
||||
'HMGET' => $getKeyFromFirstArgument,
|
||||
'HMSET' => $getKeyFromFirstArgument,
|
||||
'HINCRBY' => $getKeyFromFirstArgument,
|
||||
'HINCRBYFLOAT' => $getKeyFromFirstArgument,
|
||||
'HKEYS' => $getKeyFromFirstArgument,
|
||||
'HLEN' => $getKeyFromFirstArgument,
|
||||
'HSET' => $getKeyFromFirstArgument,
|
||||
'HSETNX' => $getKeyFromFirstArgument,
|
||||
'HVALS' => $getKeyFromFirstArgument,
|
||||
'HSCAN' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on HyperLogLog */
|
||||
'PFADD' => $getKeyFromFirstArgument,
|
||||
'PFCOUNT' => $getKeyFromAllArguments,
|
||||
'PFMERGE' => $getKeyFromAllArguments,
|
||||
|
||||
/* scripting */
|
||||
'EVAL' => array($this, 'getKeyFromScriptingCommands'),
|
||||
@@ -180,7 +189,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* associated handler for the specified command ID is removed.
|
||||
*
|
||||
* @param string $commandId The ID of the command to be handled.
|
||||
* @param mixed $callback A valid callable object or NULL.
|
||||
* @param mixed $callback A valid callable object or NULL.
|
||||
*/
|
||||
public function setCommandHandler($commandId, $callback = null)
|
||||
{
|
||||
@@ -188,6 +197,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
|
||||
if (!isset($callback)) {
|
||||
unset($this->commands[$commandId]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -201,7 +211,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from the first argument of a command instance.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromFirstArgument(CommandInterface $command)
|
||||
@@ -213,7 +223,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* Extracts the key from a command with multiple keys only when all keys
|
||||
* in the arguments array produce the same hash.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromAllArguments(CommandInterface $command)
|
||||
@@ -229,7 +239,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* Extracts the key from a command with multiple keys only when all keys
|
||||
* in the arguments array produce the same hash.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromInterleavedArguments(CommandInterface $command)
|
||||
@@ -249,7 +259,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from BLPOP and BRPOP commands.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromBlockingListCommands(CommandInterface $command)
|
||||
@@ -264,7 +274,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from BITOP command.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromBitOp(CommandInterface $command)
|
||||
@@ -279,7 +289,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from ZINTERSTORE and ZUNIONSTORE commands.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromZsetAggregationCommands(CommandInterface $command)
|
||||
@@ -295,7 +305,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from EVAL and EVALSHA commands.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
@@ -344,8 +354,8 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Checks if the specified array of keys will generate the same hash.
|
||||
*
|
||||
* @param array $keys Array of keys.
|
||||
* @return Boolean
|
||||
* @param array $keys Array of keys.
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkSameHashForKeys(Array $keys)
|
||||
{
|
||||
@@ -372,7 +382,7 @@ class PredisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* Returns only the hashable part of a key (delimited by "{...}"), or the
|
||||
* whole key if a key tag is not found in the string.
|
||||
*
|
||||
* @param string $key A key.
|
||||
* @param string $key A key.
|
||||
* @return string
|
||||
*/
|
||||
protected function extractKeyTag($key)
|
||||
|
||||
@@ -42,103 +42,113 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
protected function getDefaultCommands()
|
||||
{
|
||||
$keyIsFirstArgument = array($this, 'getKeyFromFirstArgument');
|
||||
$getKeyFromFirstArgument = array($this, 'getKeyFromFirstArgument');
|
||||
$getKeyFromAllArguments = array($this, 'getKeyFromAllArguments');
|
||||
|
||||
return array(
|
||||
/* commands operating on the key space */
|
||||
'EXISTS' => $keyIsFirstArgument,
|
||||
'DEL' => array($this, 'getKeyFromAllArguments'),
|
||||
'TYPE' => $keyIsFirstArgument,
|
||||
'EXPIRE' => $keyIsFirstArgument,
|
||||
'EXPIREAT' => $keyIsFirstArgument,
|
||||
'PERSIST' => $keyIsFirstArgument,
|
||||
'PEXPIRE' => $keyIsFirstArgument,
|
||||
'PEXPIREAT' => $keyIsFirstArgument,
|
||||
'TTL' => $keyIsFirstArgument,
|
||||
'PTTL' => $keyIsFirstArgument,
|
||||
'SORT' => $keyIsFirstArgument, // TODO
|
||||
'EXISTS' => $getKeyFromFirstArgument,
|
||||
'DEL' => $getKeyFromAllArguments,
|
||||
'TYPE' => $getKeyFromFirstArgument,
|
||||
'EXPIRE' => $getKeyFromFirstArgument,
|
||||
'EXPIREAT' => $getKeyFromFirstArgument,
|
||||
'PERSIST' => $getKeyFromFirstArgument,
|
||||
'PEXPIRE' => $getKeyFromFirstArgument,
|
||||
'PEXPIREAT' => $getKeyFromFirstArgument,
|
||||
'TTL' => $getKeyFromFirstArgument,
|
||||
'PTTL' => $getKeyFromFirstArgument,
|
||||
'SORT' => $getKeyFromFirstArgument, // TODO
|
||||
|
||||
/* commands operating on string values */
|
||||
'APPEND' => $keyIsFirstArgument,
|
||||
'DECR' => $keyIsFirstArgument,
|
||||
'DECRBY' => $keyIsFirstArgument,
|
||||
'GET' => $keyIsFirstArgument,
|
||||
'GETBIT' => $keyIsFirstArgument,
|
||||
'MGET' => array($this, 'getKeyFromAllArguments'),
|
||||
'SET' => $keyIsFirstArgument,
|
||||
'GETRANGE' => $keyIsFirstArgument,
|
||||
'GETSET' => $keyIsFirstArgument,
|
||||
'INCR' => $keyIsFirstArgument,
|
||||
'INCRBY' => $keyIsFirstArgument,
|
||||
'SETBIT' => $keyIsFirstArgument,
|
||||
'SETEX' => $keyIsFirstArgument,
|
||||
'APPEND' => $getKeyFromFirstArgument,
|
||||
'DECR' => $getKeyFromFirstArgument,
|
||||
'DECRBY' => $getKeyFromFirstArgument,
|
||||
'GET' => $getKeyFromFirstArgument,
|
||||
'GETBIT' => $getKeyFromFirstArgument,
|
||||
'MGET' => $getKeyFromAllArguments,
|
||||
'SET' => $getKeyFromFirstArgument,
|
||||
'GETRANGE' => $getKeyFromFirstArgument,
|
||||
'GETSET' => $getKeyFromFirstArgument,
|
||||
'INCR' => $getKeyFromFirstArgument,
|
||||
'INCRBY' => $getKeyFromFirstArgument,
|
||||
'INCRBYFLOAT' => $getKeyFromFirstArgument,
|
||||
'SETBIT' => $getKeyFromFirstArgument,
|
||||
'SETEX' => $getKeyFromFirstArgument,
|
||||
'MSET' => array($this, 'getKeyFromInterleavedArguments'),
|
||||
'MSETNX' => array($this, 'getKeyFromInterleavedArguments'),
|
||||
'SETNX' => $keyIsFirstArgument,
|
||||
'SETRANGE' => $keyIsFirstArgument,
|
||||
'STRLEN' => $keyIsFirstArgument,
|
||||
'SUBSTR' => $keyIsFirstArgument,
|
||||
'BITCOUNT' => $keyIsFirstArgument,
|
||||
'SETNX' => $getKeyFromFirstArgument,
|
||||
'SETRANGE' => $getKeyFromFirstArgument,
|
||||
'STRLEN' => $getKeyFromFirstArgument,
|
||||
'SUBSTR' => $getKeyFromFirstArgument,
|
||||
'BITCOUNT' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on lists */
|
||||
'LINSERT' => $keyIsFirstArgument,
|
||||
'LINDEX' => $keyIsFirstArgument,
|
||||
'LLEN' => $keyIsFirstArgument,
|
||||
'LPOP' => $keyIsFirstArgument,
|
||||
'RPOP' => $keyIsFirstArgument,
|
||||
'LINSERT' => $getKeyFromFirstArgument,
|
||||
'LINDEX' => $getKeyFromFirstArgument,
|
||||
'LLEN' => $getKeyFromFirstArgument,
|
||||
'LPOP' => $getKeyFromFirstArgument,
|
||||
'RPOP' => $getKeyFromFirstArgument,
|
||||
'BLPOP' => array($this, 'getKeyFromBlockingListCommands'),
|
||||
'BRPOP' => array($this, 'getKeyFromBlockingListCommands'),
|
||||
'LPUSH' => $keyIsFirstArgument,
|
||||
'LPUSHX' => $keyIsFirstArgument,
|
||||
'RPUSH' => $keyIsFirstArgument,
|
||||
'RPUSHX' => $keyIsFirstArgument,
|
||||
'LRANGE' => $keyIsFirstArgument,
|
||||
'LREM' => $keyIsFirstArgument,
|
||||
'LSET' => $keyIsFirstArgument,
|
||||
'LTRIM' => $keyIsFirstArgument,
|
||||
'LPUSH' => $getKeyFromFirstArgument,
|
||||
'LPUSHX' => $getKeyFromFirstArgument,
|
||||
'RPUSH' => $getKeyFromFirstArgument,
|
||||
'RPUSHX' => $getKeyFromFirstArgument,
|
||||
'LRANGE' => $getKeyFromFirstArgument,
|
||||
'LREM' => $getKeyFromFirstArgument,
|
||||
'LSET' => $getKeyFromFirstArgument,
|
||||
'LTRIM' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on sets */
|
||||
'SADD' => $keyIsFirstArgument,
|
||||
'SCARD' => $keyIsFirstArgument,
|
||||
'SISMEMBER' => $keyIsFirstArgument,
|
||||
'SMEMBERS' => $keyIsFirstArgument,
|
||||
'SSCAN' => $keyIsFirstArgument,
|
||||
'SPOP' => $keyIsFirstArgument,
|
||||
'SRANDMEMBER' => $keyIsFirstArgument,
|
||||
'SREM' => $keyIsFirstArgument,
|
||||
'SADD' => $getKeyFromFirstArgument,
|
||||
'SCARD' => $getKeyFromFirstArgument,
|
||||
'SISMEMBER' => $getKeyFromFirstArgument,
|
||||
'SMEMBERS' => $getKeyFromFirstArgument,
|
||||
'SSCAN' => $getKeyFromFirstArgument,
|
||||
'SPOP' => $getKeyFromFirstArgument,
|
||||
'SRANDMEMBER' => $getKeyFromFirstArgument,
|
||||
'SREM' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'ZADD' => $keyIsFirstArgument,
|
||||
'ZCARD' => $keyIsFirstArgument,
|
||||
'ZCOUNT' => $keyIsFirstArgument,
|
||||
'ZINCRBY' => $keyIsFirstArgument,
|
||||
'ZRANGE' => $keyIsFirstArgument,
|
||||
'ZRANGEBYSCORE' => $keyIsFirstArgument,
|
||||
'ZRANK' => $keyIsFirstArgument,
|
||||
'ZREM' => $keyIsFirstArgument,
|
||||
'ZREMRANGEBYRANK' => $keyIsFirstArgument,
|
||||
'ZREMRANGEBYSCORE' => $keyIsFirstArgument,
|
||||
'ZREVRANGE' => $keyIsFirstArgument,
|
||||
'ZREVRANGEBYSCORE' => $keyIsFirstArgument,
|
||||
'ZREVRANK' => $keyIsFirstArgument,
|
||||
'ZSCORE' => $keyIsFirstArgument,
|
||||
'ZSCAN' => $keyIsFirstArgument,
|
||||
'ZADD' => $getKeyFromFirstArgument,
|
||||
'ZCARD' => $getKeyFromFirstArgument,
|
||||
'ZCOUNT' => $getKeyFromFirstArgument,
|
||||
'ZINCRBY' => $getKeyFromFirstArgument,
|
||||
'ZRANGE' => $getKeyFromFirstArgument,
|
||||
'ZRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZRANK' => $getKeyFromFirstArgument,
|
||||
'ZREM' => $getKeyFromFirstArgument,
|
||||
'ZREMRANGEBYRANK' => $getKeyFromFirstArgument,
|
||||
'ZREMRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANGE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANGEBYSCORE' => $getKeyFromFirstArgument,
|
||||
'ZREVRANK' => $getKeyFromFirstArgument,
|
||||
'ZSCORE' => $getKeyFromFirstArgument,
|
||||
'ZSCAN' => $getKeyFromFirstArgument,
|
||||
'ZLEXCOUNT' => $getKeyFromFirstArgument,
|
||||
'ZRANGEBYLEX' => $getKeyFromFirstArgument,
|
||||
'ZREMRANGEBYLEX' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on hashes */
|
||||
'HDEL' => $keyIsFirstArgument,
|
||||
'HEXISTS' => $keyIsFirstArgument,
|
||||
'HGET' => $keyIsFirstArgument,
|
||||
'HGETALL' => $keyIsFirstArgument,
|
||||
'HMGET' => $keyIsFirstArgument,
|
||||
'HMSET' => $keyIsFirstArgument,
|
||||
'HINCRBY' => $keyIsFirstArgument,
|
||||
'HINCRBYFLOAT' => $keyIsFirstArgument,
|
||||
'HKEYS' => $keyIsFirstArgument,
|
||||
'HLEN' => $keyIsFirstArgument,
|
||||
'HSET' => $keyIsFirstArgument,
|
||||
'HSETNX' => $keyIsFirstArgument,
|
||||
'HVALS' => $keyIsFirstArgument,
|
||||
'HSCAN' => $keyIsFirstArgument,
|
||||
'HDEL' => $getKeyFromFirstArgument,
|
||||
'HEXISTS' => $getKeyFromFirstArgument,
|
||||
'HGET' => $getKeyFromFirstArgument,
|
||||
'HGETALL' => $getKeyFromFirstArgument,
|
||||
'HMGET' => $getKeyFromFirstArgument,
|
||||
'HMSET' => $getKeyFromFirstArgument,
|
||||
'HINCRBY' => $getKeyFromFirstArgument,
|
||||
'HINCRBYFLOAT' => $getKeyFromFirstArgument,
|
||||
'HKEYS' => $getKeyFromFirstArgument,
|
||||
'HLEN' => $getKeyFromFirstArgument,
|
||||
'HSET' => $getKeyFromFirstArgument,
|
||||
'HSETNX' => $getKeyFromFirstArgument,
|
||||
'HVALS' => $getKeyFromFirstArgument,
|
||||
'HSCAN' => $getKeyFromFirstArgument,
|
||||
|
||||
/* commands operating on HyperLogLog */
|
||||
'PFADD' => $getKeyFromFirstArgument,
|
||||
'PFCOUNT' => $getKeyFromAllArguments,
|
||||
'PFMERGE' => $getKeyFromAllArguments,
|
||||
|
||||
/* scripting */
|
||||
'EVAL' => array($this, 'getKeyFromScriptingCommands'),
|
||||
@@ -166,7 +176,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* associated handler for the specified command ID is removed.
|
||||
*
|
||||
* @param string $commandId The ID of the command to be handled.
|
||||
* @param mixed $callback A valid callable object or NULL.
|
||||
* @param mixed $callback A valid callable object or NULL.
|
||||
*/
|
||||
public function setCommandHandler($commandId, $callback = null)
|
||||
{
|
||||
@@ -174,6 +184,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
|
||||
if (!isset($callback)) {
|
||||
unset($this->commands[$commandId]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,7 +198,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from the first argument of a command instance.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromFirstArgument(CommandInterface $command)
|
||||
@@ -199,7 +210,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* Extracts the key from a command that can accept multiple keys ensuring
|
||||
* that only one key is actually specified to comply with redis-cluster.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromAllArguments(CommandInterface $command)
|
||||
@@ -215,7 +226,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* Extracts the key from a command that can accept multiple keys ensuring
|
||||
* that only one key is actually specified to comply with redis-cluster.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromInterleavedArguments(CommandInterface $command)
|
||||
@@ -231,7 +242,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
* Extracts the key from BLPOP and BRPOP commands ensuring that only one key
|
||||
* is actually specified to comply with redis-cluster.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromBlockingListCommands(CommandInterface $command)
|
||||
@@ -246,7 +257,7 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
/**
|
||||
* Extracts the key from EVAL and EVALSHA commands.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @return string
|
||||
*/
|
||||
protected function getKeyFromScriptingCommands(CommandInterface $command)
|
||||
@@ -286,6 +297,27 @@ class RedisClusterHashStrategy implements CommandHashStrategyInterface
|
||||
*/
|
||||
public function getKeyHash($key)
|
||||
{
|
||||
return $this->hashGenerator->hash($key);
|
||||
$key = $this->extractKeyTag($key);
|
||||
$hash = $this->hashGenerator->hash($key);
|
||||
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only the hashable part of a key (delimited by "{...}"), or the
|
||||
* whole key if a key tag is not found in the string.
|
||||
*
|
||||
* @param string $key A key.
|
||||
* @return string
|
||||
*/
|
||||
protected function extractKeyTag($key)
|
||||
{
|
||||
if (false !== $start = strpos($key, '{')) {
|
||||
if (false !== ($end = strpos($key, '}', $start)) && $end !== ++$start) {
|
||||
$key = substr($key, $start, $end - $start);
|
||||
}
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ abstract class CursorBasedIterator implements Iterator
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Client connected to Redis.
|
||||
* @param string $match Pattern to match during the server-side iteration.
|
||||
* @param int $count Hints used by Redis to compute the number of results per iteration.
|
||||
* @param string $match Pattern to match during the server-side iteration.
|
||||
* @param int $count Hints used by Redis to compute the number of results per iteration.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, $match = null, $count = null)
|
||||
{
|
||||
@@ -60,8 +60,8 @@ abstract class CursorBasedIterator implements Iterator
|
||||
* command required to fetch elements from the server to perform
|
||||
* the iteration.
|
||||
*
|
||||
* @param ClientInterface Client connected to Redis.
|
||||
* @param string $commandID Command ID.
|
||||
* @param ClientInterface $client Client connected to Redis.
|
||||
* @param string $commandID Command ID.
|
||||
*/
|
||||
protected function requiredCommand(ClientInterface $client, $commandID)
|
||||
{
|
||||
@@ -109,7 +109,7 @@ abstract class CursorBasedIterator implements Iterator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected abstract function executeCommand();
|
||||
abstract protected function executeCommand();
|
||||
|
||||
/**
|
||||
* Populates the local buffer of elements fetched from the
|
||||
@@ -166,16 +166,18 @@ abstract class CursorBasedIterator implements Iterator
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
if (!$this->elements && $this->fetchmore) {
|
||||
$this->fetch();
|
||||
}
|
||||
tryFetch: {
|
||||
if (!$this->elements && $this->fetchmore) {
|
||||
$this->fetch();
|
||||
}
|
||||
|
||||
if ($this->elements) {
|
||||
$this->extractNext();
|
||||
} else if ($this->cursor) {
|
||||
$this->next();
|
||||
} else {
|
||||
$this->valid = false;
|
||||
if ($this->elements) {
|
||||
$this->extractNext();
|
||||
} elseif ($this->cursor) {
|
||||
goto tryFetch;
|
||||
} else {
|
||||
$this->valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ class ListKey implements Iterator
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Client connected to Redis.
|
||||
* @param string $key Redis list key.
|
||||
* @param int $count Number of items retrieved on each fetch operation.
|
||||
* @param string $key Redis list key.
|
||||
* @param int $count Number of items retrieved on each fetch operation.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, $key, $count = 10)
|
||||
{
|
||||
@@ -66,8 +66,8 @@ class ListKey implements Iterator
|
||||
* command required to fetch elements from the server to perform
|
||||
* the iteration.
|
||||
*
|
||||
* @param ClientInterface Client connected to Redis.
|
||||
* @param string $commandID Command ID.
|
||||
* @param ClientInterface $client Client connected to Redis.
|
||||
* @param string $commandID Command ID.
|
||||
*/
|
||||
protected function requiredCommand(ClientInterface $client, $commandID)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ abstract class AbstractCommand implements CommandInterface
|
||||
/**
|
||||
* Returns a filtered array of the arguments.
|
||||
*
|
||||
* @param array $arguments List of arguments.
|
||||
* @param array $arguments List of arguments.
|
||||
* @return array
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
@@ -42,9 +42,7 @@ abstract class AbstractCommand implements CommandInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arguments array without filtering.
|
||||
*
|
||||
* @param array $arguments List of arguments.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRawArguments(Array $arguments)
|
||||
{
|
||||
@@ -61,9 +59,7 @@ abstract class AbstractCommand implements CommandInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument from the arguments list at the specified index.
|
||||
*
|
||||
* @param array $arguments Position of the argument.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getArgument($index)
|
||||
{
|
||||
@@ -101,8 +97,8 @@ abstract class AbstractCommand implements CommandInterface
|
||||
/**
|
||||
* Helper function used to reduce a list of arguments to a string.
|
||||
*
|
||||
* @param string $accumulator Temporary string.
|
||||
* @param string $argument Current argument.
|
||||
* @param string $accumulator Temporary string.
|
||||
* @param string $argument Current argument.
|
||||
* @return string
|
||||
*/
|
||||
protected function toStringArgumentReducer($accumulator, $argument)
|
||||
@@ -133,7 +129,7 @@ abstract class AbstractCommand implements CommandInterface
|
||||
/**
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeArguments(Array $arguments)
|
||||
@@ -148,7 +144,7 @@ abstract class AbstractCommand implements CommandInterface
|
||||
/**
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeVariadic(Array $arguments)
|
||||
|
||||
@@ -62,14 +62,15 @@ interface CommandInterface
|
||||
/**
|
||||
* Gets the argument of the command at the specified index.
|
||||
*
|
||||
* @return array
|
||||
* @param int $index Index of the desired argument.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getArgument($index);
|
||||
|
||||
/**
|
||||
* Parses a reply buffer and returns a PHP object.
|
||||
*
|
||||
* @param string $data Binary string containing the whole reply.
|
||||
* @param string $data Binary string containing the whole reply.
|
||||
* @return mixed
|
||||
*/
|
||||
public function parseResponse($data);
|
||||
|
||||
@@ -41,7 +41,7 @@ class HashScan extends PrefixableCommand
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
* @param array $options List of options.
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareOptions($options)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/pfadd
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class HyperLogLogAdd extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'PFADD';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(array $arguments)
|
||||
{
|
||||
return self::normalizeVariadic($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return (bool) $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/pfcount
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class HyperLogLogCount extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'PFCOUNT';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(array $arguments)
|
||||
{
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/pfmerge
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class HyperLogLogMerge extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'PFMERGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(array $arguments)
|
||||
{
|
||||
return self::normalizeArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::all($this, $prefix);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class KeyScan extends AbstractCommand
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
* @param array $options List of options.
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareOptions($options)
|
||||
|
||||
@@ -22,7 +22,7 @@ class PrefixHelpers
|
||||
* Applies the specified prefix only the first argument.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function first(CommandInterface $command, $prefix)
|
||||
{
|
||||
@@ -36,7 +36,7 @@ class PrefixHelpers
|
||||
* Applies the specified prefix to all the arguments.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function all(CommandInterface $command, $prefix)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ class PrefixHelpers
|
||||
* Applies the specified prefix only to even arguments in the list.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function interleaved(CommandInterface $command, $prefix)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ class PrefixHelpers
|
||||
* Applies the specified prefix to all the arguments but the first one.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function skipFirst(CommandInterface $command, $prefix)
|
||||
{
|
||||
@@ -91,7 +91,7 @@ class PrefixHelpers
|
||||
* Applies the specified prefix to all the arguments but the last one.
|
||||
*
|
||||
* @param CommandInterface $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function skipLast(CommandInterface $command, $prefix)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Class for generic "anonymous" Redis commands.
|
||||
*
|
||||
* This command class does not filter input arguments or parse responses, but
|
||||
* can be used to leverage the standard Predis API to execute any command simply
|
||||
* by providing the needed arguments following the command signature as defined
|
||||
* by Redis in its documentation.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class RawCommand implements CommandInterface
|
||||
{
|
||||
private $hash;
|
||||
private $commandID;
|
||||
private $arguments;
|
||||
|
||||
public function __construct(array $arguments)
|
||||
{
|
||||
if (!$arguments) {
|
||||
throw new InvalidArgumentException("Arguments array is missing the command ID");
|
||||
}
|
||||
|
||||
$this->commandID = strtoupper(array_shift($arguments));
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new raw command using a variadic method.
|
||||
*
|
||||
* @param string $commandID Redis command ID.
|
||||
* @param string ... Arguments list for the command.
|
||||
* @return CommandInterface
|
||||
*/
|
||||
public static function create($commandID /* [ $arg, ... */)
|
||||
{
|
||||
$arguments = func_get_args();
|
||||
$command = new self($arguments);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->commandID;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
unset($this->hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRawArguments(array $arguments)
|
||||
{
|
||||
$this->setArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getArgument($index)
|
||||
{
|
||||
if (isset($this->arguments[$index])) {
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setHash($hash)
|
||||
{
|
||||
$this->hash = $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHash()
|
||||
{
|
||||
if (isset($this->hash)) {
|
||||
return $this->hash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function used to reduce a list of arguments to a string.
|
||||
*
|
||||
* @param string $accumulator Temporary string.
|
||||
* @param string $argument Current argument.
|
||||
* @return string
|
||||
*/
|
||||
protected function toStringArgumentReducer($accumulator, $argument)
|
||||
{
|
||||
if (strlen($argument) > 32) {
|
||||
$argument = substr($argument, 0, 32) . '[...]';
|
||||
}
|
||||
|
||||
$accumulator .= " $argument";
|
||||
|
||||
return $accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial string representation of the command with its arguments.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return array_reduce(
|
||||
$this->getArguments(),
|
||||
array($this, 'toStringArgumentReducer'),
|
||||
$this->getId()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ abstract class ScriptedCommand extends ServerEvalSHA
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public abstract function getScript();
|
||||
abstract public function getScript();
|
||||
|
||||
/**
|
||||
* Specifies the number of arguments that should be considered as keys.
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/client
|
||||
* @link http://redis.io/commands/client-list
|
||||
* @link http://redis.io/commands/client-kill
|
||||
* @link http://redis.io/commands/client-getname
|
||||
* @link http://redis.io/commands/client-setname
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ServerClient extends AbstractCommand
|
||||
@@ -47,7 +50,7 @@ class ServerClient extends AbstractCommand
|
||||
* Parses the reply buffer and returns the list of clients returned by
|
||||
* the CLIENT LIST command.
|
||||
*
|
||||
* @param string $data Reply buffer
|
||||
* @param string $data Reply buffer
|
||||
* @return array
|
||||
*/
|
||||
protected function parseClientList($data)
|
||||
|
||||
@@ -34,31 +34,41 @@ class ServerInfo extends AbstractCommand
|
||||
$infoLines = preg_split('/\r?\n/', $data);
|
||||
|
||||
foreach ($infoLines as $row) {
|
||||
@list($k, $v) = explode(':', $row);
|
||||
|
||||
if ($row === '' || !isset($v)) {
|
||||
if (strpos($row, ':') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!preg_match('/^db\d+$/', $k)) {
|
||||
if ($k === 'allocation_stats') {
|
||||
$info[$k] = $this->parseAllocationStats($v);
|
||||
continue;
|
||||
}
|
||||
|
||||
$info[$k] = $v;
|
||||
} else {
|
||||
$info[$k] = $this->parseDatabaseStats($v);
|
||||
}
|
||||
list($k, $v) = $this->parseRow($row);
|
||||
$info[$k] = $v;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses single row of the reply buffer and returns the key-value pair.
|
||||
*
|
||||
* @param string $row Single row of the reply buffer.
|
||||
* @return array
|
||||
*/
|
||||
public function parseRow($row)
|
||||
{
|
||||
list($k, $v) = explode(':', $row, 2);
|
||||
|
||||
if (!preg_match('/^db\d+$/', $k)) {
|
||||
if ($k === 'allocation_stats') {
|
||||
$v = $this->parseAllocationStats($v);
|
||||
}
|
||||
} else {
|
||||
$v = $this->parseDatabaseStats($v);
|
||||
}
|
||||
return array($k, $v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the reply buffer and extracts the statistics of each logical DB.
|
||||
*
|
||||
* @param string $str Reply buffer.
|
||||
* @param string $str Reply buffer.
|
||||
* @return array
|
||||
*/
|
||||
protected function parseDatabaseStats($str)
|
||||
@@ -76,7 +86,7 @@ class ServerInfo extends AbstractCommand
|
||||
/**
|
||||
* Parses the reply buffer and extracts the allocation statistics.
|
||||
*
|
||||
* @param string $str Reply buffer.
|
||||
* @param string $str Reply buffer.
|
||||
* @return array
|
||||
*/
|
||||
protected function parseAllocationStats($str)
|
||||
|
||||
@@ -41,18 +41,8 @@ class ServerInfoV26x extends ServerInfo
|
||||
continue;
|
||||
}
|
||||
|
||||
list($k, $v) = explode(':', $row);
|
||||
|
||||
if (!preg_match('/^db\d+$/', $k)) {
|
||||
if ($k === 'allocation_stats') {
|
||||
$current[$k] = $this->parseAllocationStats($v);
|
||||
continue;
|
||||
}
|
||||
|
||||
$current[$k] = $v;
|
||||
} else {
|
||||
$current[$k] = $this->parseDatabaseStats($v);
|
||||
}
|
||||
list($k, $v) = $this->parseRow($row);
|
||||
$current[$k] = $v;
|
||||
}
|
||||
|
||||
return $info;
|
||||
|
||||
@@ -41,7 +41,7 @@ class SetScan extends PrefixableCommand
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
* @param array $options List of options.
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareOptions($options)
|
||||
|
||||
@@ -33,7 +33,7 @@ class ZSetAdd extends PrefixableCommand
|
||||
if (count($arguments) === 2 && is_array($arguments[1])) {
|
||||
$flattened = array($arguments[0]);
|
||||
|
||||
foreach($arguments[1] as $member => $score) {
|
||||
foreach ($arguments[1] as $member => $score) {
|
||||
$flattened[] = $score;
|
||||
$flattened[] = $member;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zlexcount
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ZSetLexCount extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'ZLEXCOUNT';
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ class ZSetRange extends PrefixableCommand
|
||||
|
||||
if ($lastType === 'array') {
|
||||
$options = $this->prepareOptions(array_pop($arguments));
|
||||
|
||||
return array_merge($arguments, $options);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +52,7 @@ class ZSetRange extends PrefixableCommand
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
* @param array $options List of options.
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareOptions($options)
|
||||
@@ -69,7 +70,7 @@ class ZSetRange extends PrefixableCommand
|
||||
/**
|
||||
* Checks for the presence of the WITHSCORES modifier.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
protected function withScores()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zrangebylex
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ZSetRangeByLex extends ZSetRange
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'ZRANGEBYLEX';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function prepareOptions($options)
|
||||
{
|
||||
$opts = array_change_key_case($options, CASE_UPPER);
|
||||
$finalizedOpts = array();
|
||||
|
||||
if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
|
||||
$limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);
|
||||
|
||||
$finalizedOpts[] = 'LIMIT';
|
||||
$finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0];
|
||||
$finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1];
|
||||
}
|
||||
|
||||
return $finalizedOpts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function withScores()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/zremrangebylex
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class ZSetRemoveRangeByLex extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'ZREMRANGEBYLEX';
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class ZSetScan extends PrefixableCommand
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
* @param array $options List of options.
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareOptions($options)
|
||||
|
||||
@@ -50,7 +50,7 @@ class ZSetUnionStore extends PrefixableCommand
|
||||
/**
|
||||
* Returns a list of options and modifiers compatible with Redis.
|
||||
*
|
||||
* @param array $options List of options.
|
||||
* @param array $options List of options.
|
||||
* @return array
|
||||
*/
|
||||
private function prepareOptions($options)
|
||||
|
||||
@@ -23,10 +23,10 @@ abstract class CommunicationException extends PredisException
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @param SingleConnectionInterface $connection Connection that generated the exception.
|
||||
* @param string $message Error message.
|
||||
* @param int $code Error code.
|
||||
* @param \Exception $innerException Inner exception for wrapping the original error.
|
||||
* @param SingleConnectionInterface $connection Connection that generated the exception.
|
||||
* @param string $message Error message.
|
||||
* @param int $code Error code.
|
||||
* @param \Exception $innerException Inner exception for wrapping the original error.
|
||||
*/
|
||||
public function __construct(
|
||||
SingleConnectionInterface $connection, $message = null, $code = null, \Exception $innerException = null
|
||||
@@ -48,7 +48,7 @@ abstract class CommunicationException extends PredisException
|
||||
/**
|
||||
* Indicates if the receiver should reset the underlying connection.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldResetConnection()
|
||||
{
|
||||
|
||||
@@ -50,7 +50,8 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
/**
|
||||
* Checks some of the parameters used to initialize the connection.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Initialization parameters for the connection.
|
||||
* @return ConnectionParametersInterface
|
||||
*/
|
||||
protected function checkParameters(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
@@ -73,7 +74,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function createResource();
|
||||
abstract protected function createResource();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -117,6 +118,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
public function executeCommand(CommandInterface $command)
|
||||
{
|
||||
$this->writeCommand($command);
|
||||
|
||||
return $this->readResponse($command);
|
||||
}
|
||||
|
||||
@@ -132,7 +134,7 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
* Helper method to handle connection errors.
|
||||
*
|
||||
* @param string $message Error message.
|
||||
* @param int $code Error code.
|
||||
* @param int $code Error code.
|
||||
*/
|
||||
protected function onConnectionError($message, $code = null)
|
||||
{
|
||||
@@ -152,8 +154,8 @@ abstract class AbstractConnection implements SingleConnectionInterface
|
||||
/**
|
||||
* Helper method to handle not supported connection parameters.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @param mixed $parameters Parameters used to initialize the connection.
|
||||
* @param string $option Name of the option.
|
||||
* @param mixed $parameters Parameters used to initialize the connection.
|
||||
*/
|
||||
protected function onInvalidOption($option, $parameters = null)
|
||||
{
|
||||
|
||||
@@ -31,15 +31,15 @@ interface AggregatedConnectionInterface extends ConnectionInterface
|
||||
* Removes the specified connection instance from the aggregated
|
||||
* connection.
|
||||
*
|
||||
* @param SingleConnectionInterface $connection Instance of a connection.
|
||||
* @return Boolean Returns true if the connection was in the pool.
|
||||
* @param SingleConnectionInterface $connection Instance of a connection.
|
||||
* @return bool Returns true if the connection was in the pool.
|
||||
*/
|
||||
public function remove(SingleConnectionInterface $connection);
|
||||
|
||||
/**
|
||||
* Gets the actual connection instance in charge of the specified command.
|
||||
*
|
||||
* @param CommandInterface $command Instance of a Redis command.
|
||||
* @param CommandInterface $command Instance of a Redis command.
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function getConnection(CommandInterface $command);
|
||||
@@ -48,7 +48,7 @@ interface AggregatedConnectionInterface extends ConnectionInterface
|
||||
* Retrieves a connection instance from the aggregated connection
|
||||
* using an alias.
|
||||
*
|
||||
* @param string $connectionId Alias of a connection
|
||||
* @param string $connectionId Alias of a connection
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function getConnectionById($connectionId);
|
||||
|
||||
@@ -27,7 +27,7 @@ class ComposableStreamConnection extends StreamConnection implements ComposableC
|
||||
|
||||
/**
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ProtocolInterface $protocol A protocol processor.
|
||||
* @param ProtocolInterface $protocol A protocol processor.
|
||||
*/
|
||||
public function __construct(ConnectionParametersInterface $parameters, ProtocolInterface $protocol = null)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\Profile\ServerProfile;
|
||||
use Predis\Profile\ServerProfileInterface;
|
||||
|
||||
/**
|
||||
@@ -55,7 +54,7 @@ class ConnectionFactory implements ConnectionFactoryInterface
|
||||
* implementing Predis\Connection\SingleConnectionInterface. Optionally,
|
||||
* callable objects are used for lazy initialization of connection objects.
|
||||
*
|
||||
* @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
|
||||
* @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function checkInitializer($initializer)
|
||||
|
||||
@@ -22,8 +22,8 @@ interface ConnectionFactoryInterface
|
||||
/**
|
||||
* Defines or overrides the connection class identified by a scheme prefix.
|
||||
*
|
||||
* @param string $scheme URI scheme identifying the connection class.
|
||||
* @param mixed $initializer FQN of a connection class or a callable object for lazy initialization.
|
||||
* @param string $scheme URI scheme identifying the connection class.
|
||||
* @param mixed $initializer FQN of a connection class or a callable object for lazy initialization.
|
||||
*/
|
||||
public function define($scheme, $initializer);
|
||||
|
||||
@@ -37,7 +37,7 @@ interface ConnectionFactoryInterface
|
||||
/**
|
||||
* Creates a new connection object.
|
||||
*
|
||||
* @param mixed $parameters Parameters for the connection.
|
||||
* @param mixed $parameters Parameters for the connection.
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function create($parameters);
|
||||
@@ -45,8 +45,8 @@ interface ConnectionFactoryInterface
|
||||
/**
|
||||
* Prepares an aggregation of connection objects.
|
||||
*
|
||||
* @param AggregatedConnectionInterface $cluster Instance of an aggregated connection class.
|
||||
* @param array $parameters List of parameters for each connection object.
|
||||
* @param AggregatedConnectionInterface $cluster Instance of an aggregated connection class.
|
||||
* @param array $parameters List of parameters for each connection object.
|
||||
* @return AggregatedConnectionInterface
|
||||
*/
|
||||
public function createAggregated(AggregatedConnectionInterface $cluster, Array $parameters);
|
||||
|
||||
@@ -34,7 +34,7 @@ interface ConnectionInterface
|
||||
/**
|
||||
* Returns if the connection is open.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isConnected();
|
||||
|
||||
@@ -48,7 +48,7 @@ interface ConnectionInterface
|
||||
/**
|
||||
* Reads the reply for a Redis command from the connection.
|
||||
*
|
||||
* @param CommandInterface $command Instance of a Redis command.
|
||||
* @param CommandInterface $command Instance of a Redis command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function readResponse(CommandInterface $command);
|
||||
@@ -56,7 +56,7 @@ interface ConnectionInterface
|
||||
/**
|
||||
* Writes a Redis command to the connection and reads back the reply.
|
||||
*
|
||||
* @param CommandInterface $command Instance of a Redis command.
|
||||
* @param CommandInterface $command Instance of a Redis command.
|
||||
* @return mixed
|
||||
*/
|
||||
public function executeCommand(CommandInterface $command);
|
||||
|
||||
@@ -30,7 +30,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
);
|
||||
|
||||
/**
|
||||
* @param string|array Connection parameters in the form of an URI string or a named array.
|
||||
* @param string|array $parameters Connection parameters in the form of an URI string or a named array.
|
||||
*/
|
||||
public function __construct($parameters = array())
|
||||
{
|
||||
@@ -71,8 +71,8 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
/**
|
||||
* Validates value as boolean.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @return boolean
|
||||
* @param mixed $value Input value.
|
||||
* @return bool
|
||||
*/
|
||||
private static function castBoolean($value)
|
||||
{
|
||||
@@ -82,7 +82,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
/**
|
||||
* Validates value as float.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @param mixed $value Input value.
|
||||
* @return float
|
||||
*/
|
||||
private static function castFloat($value)
|
||||
@@ -93,7 +93,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
/**
|
||||
* Validates value as integer.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @param mixed $value Input value.
|
||||
* @return int
|
||||
*/
|
||||
private static function castInteger($value)
|
||||
@@ -104,7 +104,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
/**
|
||||
* Parses an URI string and returns an array of connection parameters.
|
||||
*
|
||||
* @param string $uri Connection string.
|
||||
* @param string $uri Connection string.
|
||||
* @return array
|
||||
*/
|
||||
public static function parseURI($uri)
|
||||
@@ -119,12 +119,10 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
}
|
||||
|
||||
if (isset($parsed['query'])) {
|
||||
foreach (explode('&', $parsed['query']) as $kv) {
|
||||
@list($k, $v) = explode('=', $kv);
|
||||
$parsed[$k] = $v;
|
||||
}
|
||||
|
||||
parse_str($parsed['query'], $queryarray);
|
||||
unset($parsed['query']);
|
||||
|
||||
$parsed = array_merge($parsed, $queryarray);
|
||||
}
|
||||
|
||||
return $parsed;
|
||||
@@ -133,7 +131,7 @@ class ConnectionParameters implements ConnectionParametersInterface
|
||||
/**
|
||||
* Validates and converts each value of the connection parameters array.
|
||||
*
|
||||
* @param array $parameters Connection parameters.
|
||||
* @param array $parameters Connection parameters.
|
||||
* @return array
|
||||
*/
|
||||
private function filter(Array $parameters)
|
||||
|
||||
@@ -22,15 +22,15 @@ interface ConnectionParametersInterface
|
||||
/**
|
||||
* Checks if the specified parameters is set.
|
||||
*
|
||||
* @param string $property Name of the property.
|
||||
* @return Boolean
|
||||
* @param string $parameter Name of the parameter.
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($parameter);
|
||||
|
||||
/**
|
||||
* Returns the value of the specified parameter.
|
||||
*
|
||||
* @param string $parameter Name of the parameter.
|
||||
* @param string $parameter Name of the parameter.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($parameter);
|
||||
|
||||
@@ -37,6 +37,7 @@ use Predis\Command\CommandInterface;
|
||||
* - scheme: it can be either 'tcp' or 'unix'.
|
||||
* - host: hostname or IP address of the server.
|
||||
* - port: TCP port of the server.
|
||||
* - path: path of a UNIX domain socket when scheme is 'unix'.
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
*
|
||||
@@ -136,7 +137,6 @@ class PhpiredisConnection extends AbstractConnection
|
||||
/**
|
||||
* Gets the handler used by the protocol reader to handle Redis errors.
|
||||
*
|
||||
* @param Boolean $throw_errors Specify if Redis errors throw exceptions.
|
||||
* @return \Closure
|
||||
*/
|
||||
private function getErrorHandler()
|
||||
@@ -183,7 +183,7 @@ class PhpiredisConnection extends AbstractConnection
|
||||
/**
|
||||
* Sets options on the socket resource from the connection parameters.
|
||||
*
|
||||
* @param resource $socket Socket resource.
|
||||
* @param resource $socket Socket resource.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
*/
|
||||
private function setSocketOptions($socket, ConnectionParametersInterface $parameters)
|
||||
@@ -223,10 +223,10 @@ class PhpiredisConnection extends AbstractConnection
|
||||
/**
|
||||
* Gets the address from the connection parameters.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @return string
|
||||
*/
|
||||
private function getAddress(ConnectionParametersInterface $parameters)
|
||||
protected static function getAddress(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
if ($parameters->scheme === 'unix') {
|
||||
return $parameters->path;
|
||||
@@ -235,9 +235,10 @@ class PhpiredisConnection extends AbstractConnection
|
||||
$host = $parameters->host;
|
||||
|
||||
if (ip2long($host) === false) {
|
||||
if (($addresses = gethostbynamel($host)) === false) {
|
||||
$this->onConnectionError("Cannot resolve the address of $host");
|
||||
if (false === $addresses = gethostbynamel($host)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $addresses[array_rand($addresses)];
|
||||
}
|
||||
|
||||
@@ -247,12 +248,15 @@ class PhpiredisConnection extends AbstractConnection
|
||||
/**
|
||||
* Opens the actual connection to the server with a timeout.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @return string
|
||||
*/
|
||||
private function connectWithTimeout(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
$host = self::getAddress($parameters);
|
||||
if (false === $host = self::getAddress($parameters)) {
|
||||
$this->onConnectionError("Cannot resolve the address of '$parameters->host'.");
|
||||
}
|
||||
|
||||
$socket = $this->getResource();
|
||||
|
||||
socket_set_nonblock($socket);
|
||||
|
||||
@@ -37,6 +37,7 @@ use Predis\Command\CommandInterface;
|
||||
* - scheme: it can be either 'tcp' or 'unix'.
|
||||
* - host: hostname or IP address of the server.
|
||||
* - port: TCP port of the server.
|
||||
* - path: path of a UNIX domain socket when scheme is 'unix'.
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
@@ -132,7 +133,6 @@ class PhpiredisStreamConnection extends StreamConnection
|
||||
/**
|
||||
* Gets the handler used by the protocol reader to handle Redis errors.
|
||||
*
|
||||
* @param Boolean $throw_errors Specify if Redis errors throw exceptions.
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getErrorHandler()
|
||||
@@ -151,11 +151,10 @@ class PhpiredisStreamConnection extends StreamConnection
|
||||
$reader = $this->reader;
|
||||
|
||||
while (PHPIREDIS_READER_STATE_INCOMPLETE === $state = phpiredis_reader_get_state($reader)) {
|
||||
$buffer = fread($socket, 4096);
|
||||
$buffer = stream_socket_recvfrom($socket, 4096);
|
||||
|
||||
if ($buffer === false || $buffer === '') {
|
||||
$this->onConnectionError('Error while reading bytes from the server');
|
||||
return;
|
||||
}
|
||||
|
||||
phpiredis_reader_feed($reader, $buffer);
|
||||
|
||||
@@ -112,8 +112,8 @@ class PredisCluster implements ClusterConnectionInterface, \IteratorAggregate, \
|
||||
/**
|
||||
* Removes a connection instance using its alias or index.
|
||||
*
|
||||
* @param string $connectionId Alias or index of a connection.
|
||||
* @return Boolean Returns true if the connection was in the pool.
|
||||
* @param string $connectionId Alias or index of a connection.
|
||||
* @return bool Returns true if the connection was in the pool.
|
||||
*/
|
||||
public function removeById($connectionId)
|
||||
{
|
||||
@@ -151,7 +151,7 @@ class PredisCluster implements ClusterConnectionInterface, \IteratorAggregate, \
|
||||
/**
|
||||
* Retrieves a connection instance from the cluster using a key.
|
||||
*
|
||||
* @param string $key Key of a Redis value.
|
||||
* @param string $key Key of a Redis value.
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function getConnectionByKey($key)
|
||||
@@ -216,7 +216,7 @@ class PredisCluster implements ClusterConnectionInterface, \IteratorAggregate, \
|
||||
/**
|
||||
* Executes the specified Redis command on all the nodes of a cluster.
|
||||
*
|
||||
* @param CommandInterface $command A Redis command.
|
||||
* @param CommandInterface $command A Redis command.
|
||||
* @return array
|
||||
*/
|
||||
public function executeCommandOnNodes(CommandInterface $command)
|
||||
|
||||
@@ -11,24 +11,46 @@
|
||||
|
||||
namespace Predis\Connection;
|
||||
|
||||
use Predis\ClientException;
|
||||
use Predis\Cluster\CommandHashStrategyInterface;
|
||||
use ArrayIterator;
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use OutOfBoundsException;
|
||||
use Predis\NotSupportedException;
|
||||
use Predis\ResponseErrorInterface;
|
||||
use Predis\Cluster\CommandHashStrategyInterface;
|
||||
use Predis\Cluster\RedisClusterHashStrategy;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\RawCommand;
|
||||
|
||||
/**
|
||||
* Abstraction for Redis cluster (Redis v3.0).
|
||||
* Abstraction for a Redis-backed cluster of nodes (Redis >= 3.0.0).
|
||||
*
|
||||
* This connection backend offers smart support for redis-cluster by handling
|
||||
* automatic slots map (re)generation upon -MOVE or -ASK responses returned by
|
||||
* Redis when redirecting a client to a different node.
|
||||
*
|
||||
* The cluster can be pre-initialized using only a subset of the actual nodes in
|
||||
* the cluster, Predis will do the rest by adjusting the slots map and creating
|
||||
* the missing underlying connection instances on the fly.
|
||||
*
|
||||
* It is possible to pre-associate connections to a slots range with the "slots"
|
||||
* parameter in the form "$first-$last". This can greatly reduce runtime node
|
||||
* guessing and redirections.
|
||||
*
|
||||
* It is also possible to ask for the full and updated slots map directly to one
|
||||
* of the nodes and optionally enable such a behaviour upon -MOVED redirections.
|
||||
* Asking for the cluster configuration to Redis is actually done by issuing a
|
||||
* CLUSTER NODES command to a random node in the pool.
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \Countable
|
||||
class RedisCluster implements ClusterConnectionInterface, IteratorAggregate, Countable
|
||||
{
|
||||
private $pool;
|
||||
private $slots;
|
||||
private $askClusterNodes = false;
|
||||
private $defaultParameters = array();
|
||||
private $pool = array();
|
||||
private $slots = array();
|
||||
private $slotsMap;
|
||||
private $slotsPerNode;
|
||||
private $strategy;
|
||||
private $connections;
|
||||
|
||||
@@ -37,8 +59,6 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function __construct(ConnectionFactoryInterface $connections = null)
|
||||
{
|
||||
$this->pool = array();
|
||||
$this->slots = array();
|
||||
$this->strategy = new RedisClusterHashStrategy();
|
||||
$this->connections = $connections ?: new ConnectionFactory();
|
||||
}
|
||||
@@ -62,7 +82,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
foreach ($this->pool as $connection) {
|
||||
if ($connection = $this->getRandomConnection()) {
|
||||
$connection->connect();
|
||||
}
|
||||
}
|
||||
@@ -83,10 +103,7 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
public function add(SingleConnectionInterface $connection)
|
||||
{
|
||||
$this->pool[(string) $connection] = $connection;
|
||||
unset(
|
||||
$this->slotsMap,
|
||||
$this->slotsPerNode
|
||||
);
|
||||
unset($this->slotsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,11 +111,10 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
*/
|
||||
public function remove(SingleConnectionInterface $connection)
|
||||
{
|
||||
if (($id = array_search($connection, $this->pool, true)) !== false) {
|
||||
if (false !== $id = array_search($connection, $this->pool, true)) {
|
||||
unset(
|
||||
$this->pool[$id],
|
||||
$this->slotsMap,
|
||||
$this->slotsPerNode
|
||||
$this->slotsMap
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -108,18 +124,17 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a connection instance using its alias or index.
|
||||
* Removes a connection instance by using its identifier.
|
||||
*
|
||||
* @param string $connectionId Alias or index of a connection.
|
||||
* @return Boolean Returns true if the connection was in the pool.
|
||||
* @param string $connectionID Connection identifier.
|
||||
* @return bool True if the connection was in the pool.
|
||||
*/
|
||||
public function removeById($connectionId)
|
||||
public function removeById($connectionID)
|
||||
{
|
||||
if (isset($this->pool[$connectionId])) {
|
||||
if (isset($this->pool[$connectionID])) {
|
||||
unset(
|
||||
$this->pool[$connectionId],
|
||||
$this->slotsMap,
|
||||
$this->slotsPerNode
|
||||
$this->pool[$connectionID],
|
||||
$this->slotsMap
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -129,14 +144,17 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the slots map for the cluster.
|
||||
* Generates the current slots map by guessing the cluster configuration out
|
||||
* of the connection parameters of the connections in the pool.
|
||||
*
|
||||
* @return array
|
||||
* Generation is based on the same algorithm used by Redis to generate the
|
||||
* cluster, so it is most effective when all of the connections supplied on
|
||||
* initialization have the "slots" parameter properly set accordingly to the
|
||||
* current cluster configuration.
|
||||
*/
|
||||
public function buildSlotsMap()
|
||||
{
|
||||
$this->slotsMap = array();
|
||||
$this->slotsPerNode = (int) (16384 / count($this->pool));
|
||||
|
||||
foreach ($this->pool as $connectionID => $connection) {
|
||||
$parameters = $connection->getParameters();
|
||||
@@ -145,11 +163,42 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
continue;
|
||||
}
|
||||
|
||||
list($first, $last) = explode('-', $parameters->slots, 2);
|
||||
$this->setSlots($first, $last, $connectionID);
|
||||
$slots = explode('-', $parameters->slots, 2);
|
||||
$this->setSlots($slots[0], $slots[1], $connectionID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the current slots map by fetching the cluster configuration to
|
||||
* one of the nodes by leveraging the CLUSTER NODES command.
|
||||
*/
|
||||
public function askClusterNodes()
|
||||
{
|
||||
if (!$connection = $this->getRandomConnection()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->slotsMap;
|
||||
$cmdCluster = RawCommand::create('CLUSTER', 'NODES');
|
||||
$response = $connection->executeCommand($cmdCluster);
|
||||
|
||||
$nodes = explode("\n", $response, -1);
|
||||
$count = count($nodes);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$node = explode(' ', $nodes[$i], 9);
|
||||
|
||||
if (false === strpos($node[2], 'master')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$slots = explode('-', $node[8], 2);
|
||||
|
||||
if ($node[1] === ':0') {
|
||||
$this->setSlots($slots[0], $slots[1], (string) $connection);
|
||||
} else {
|
||||
$this->setSlots($slots[0], $slots[1], $node[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,79 +216,34 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
}
|
||||
|
||||
/**
|
||||
* Preassociate a connection to a set of slots to avoid runtime guessing.
|
||||
* Pre-associates a connection to a slots range to avoid runtime guessing.
|
||||
*
|
||||
* @todo Check type or existence of the specified connection.
|
||||
* @todo Cluster loses the slots assigned with this methods when adding / removing connections.
|
||||
*
|
||||
* @param int $first Initial slot.
|
||||
* @param int $last Last slot.
|
||||
* @param int $first Initial slot of the range.
|
||||
* @param int $last Last slot of the range.
|
||||
* @param SingleConnectionInterface|string $connection ID or connection instance.
|
||||
*/
|
||||
public function setSlots($first, $last, $connection)
|
||||
{
|
||||
if ($first < 0x0000 || $first > 0x3FFF || $last < 0x0000 || $last > 0x3FFF || $last < $first) {
|
||||
throw new \OutOfBoundsException("Invalid slot values for $connection: [$first-$last]");
|
||||
if ($first < 0x0000 || $first > 0x3FFF ||
|
||||
$last < 0x0000 || $last > 0x3FFF ||
|
||||
$last < $first
|
||||
) {
|
||||
throw new OutOfBoundsException(
|
||||
"Invalid slot range for $connection: [$first-$last]"
|
||||
);
|
||||
}
|
||||
|
||||
$this->slotsMap = $this->getSlotsMap() + array_fill($first, $last - $first + 1, (string) $connection);
|
||||
$slots = array_fill($first, $last - $first + 1, (string) $connection);
|
||||
$this->slotsMap = $this->getSlotsMap() + $slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConnection(CommandInterface $command)
|
||||
{
|
||||
$hash = $this->strategy->getHash($command);
|
||||
|
||||
if (!isset($hash)) {
|
||||
throw new NotSupportedException("Cannot use {$command->getId()} with redis-cluster");
|
||||
}
|
||||
|
||||
$slot = $hash & 0x3FFF;
|
||||
|
||||
if (isset($this->slots[$slot])) {
|
||||
return $this->slots[$slot];
|
||||
}
|
||||
|
||||
$this->slots[$slot] = $connection = $this->pool[$this->guessNode($slot)];
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection associated to the specified slot.
|
||||
* Guesses the correct node associated to a given slot using a precalculated
|
||||
* slots map, falling back to the same logic used by Redis to initialize a
|
||||
* cluster (best-effort).
|
||||
*
|
||||
* @param int $slot Slot ID.
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function getConnectionBySlot($slot)
|
||||
{
|
||||
if ($slot < 0x0000 || $slot > 0x3FFF) {
|
||||
throw new \OutOfBoundsException("Invalid slot value [$slot]");
|
||||
}
|
||||
|
||||
if (isset($this->slots[$slot])) {
|
||||
return $this->slots[$slot];
|
||||
}
|
||||
|
||||
return $this->pool[$this->guessNode($slot)];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConnectionById($connectionId)
|
||||
{
|
||||
return isset($this->pool[$connectionId]) ? $this->pool[$connectionId] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries guessing the correct node associated to the given slot using a precalculated
|
||||
* slots map or the same logic used by redis-trib to initialize a redis cluster.
|
||||
*
|
||||
* @param int $slot Slot ID.
|
||||
* @return string
|
||||
* @param int $slot Slot index.
|
||||
* @return string Connection ID.
|
||||
*/
|
||||
protected function guessNode($slot)
|
||||
{
|
||||
@@ -251,51 +255,109 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
return $this->slotsMap[$slot];
|
||||
}
|
||||
|
||||
$index = min((int) ($slot / $this->slotsPerNode), count($this->pool) - 1);
|
||||
$count = count($this->pool);
|
||||
$index = min((int) ($slot / (int) (16384 / $count)), $count - 1);
|
||||
$nodes = array_keys($this->pool);
|
||||
|
||||
return $nodes[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles -MOVED or -ASK replies by re-executing the command on the server
|
||||
* specified by the Redis reply.
|
||||
* Creates a new connection instance from the given connection ID.
|
||||
*
|
||||
* @param CommandInterface $command Command that generated the -MOVE or -ASK reply.
|
||||
* @param string $request Type of request (either 'MOVED' or 'ASK').
|
||||
* @param string $details Parameters of the MOVED/ASK request.
|
||||
* @return mixed
|
||||
* @param string $connectionID Identifier for the connection.
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
protected function onMoveRequest(CommandInterface $command, $request, $details)
|
||||
protected function createConnection($connectionID)
|
||||
{
|
||||
list($slot, $host) = explode(' ', $details, 2);
|
||||
$connection = $this->getConnectionById($host);
|
||||
$host = explode(':', $connectionID, 2);
|
||||
|
||||
if (!isset($connection)) {
|
||||
$parameters = array('host' => null, 'port' => null);
|
||||
list($parameters['host'], $parameters['port']) = explode(':', $host, 2);
|
||||
$connection = $this->connections->create($parameters);
|
||||
$parameters = array_merge($this->defaultParameters, array(
|
||||
'host' => $host[0],
|
||||
'port' => $host[1],
|
||||
));
|
||||
|
||||
$connection = $this->connections->create($parameters);
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConnection(CommandInterface $command)
|
||||
{
|
||||
$hash = $this->strategy->getHash($command);
|
||||
|
||||
if (!isset($hash)) {
|
||||
throw new NotSupportedException(
|
||||
"Cannot use {$command->getId()} with redis-cluster"
|
||||
);
|
||||
}
|
||||
|
||||
switch ($request) {
|
||||
case 'MOVED':
|
||||
$this->move($connection, $slot);
|
||||
return $this->executeCommand($command);
|
||||
$slot = $hash & 0x3FFF;
|
||||
|
||||
case 'ASK':
|
||||
return $connection->executeCommand($command);
|
||||
|
||||
default:
|
||||
throw new ClientException("Unexpected request type for a move request: $request");
|
||||
if (isset($this->slots[$slot])) {
|
||||
return $this->slots[$slot];
|
||||
} else {
|
||||
return $this->getConnectionBySlot($slot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the connection instance to a new slot and adds it to the
|
||||
* pool if the connection was not already part of the pool.
|
||||
* Returns the connection currently associated to a given slot.
|
||||
*
|
||||
* @param SingleConnectionInterface $connection Connection instance
|
||||
* @param int $slot Target slot.
|
||||
* @param int $slot Slot index.
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
public function getConnectionBySlot($slot)
|
||||
{
|
||||
if ($slot < 0x0000 || $slot > 0x3FFF) {
|
||||
throw new OutOfBoundsException("Invalid slot [$slot]");
|
||||
}
|
||||
|
||||
if (isset($this->slots[$slot])) {
|
||||
return $this->slots[$slot];
|
||||
}
|
||||
|
||||
$connectionID = $this->guessNode($slot);
|
||||
|
||||
if (!$connection = $this->getConnectionById($connectionID)) {
|
||||
$connection = $this->createConnection($connectionID);
|
||||
$this->pool[$connectionID] = $connection;
|
||||
}
|
||||
|
||||
return $this->slots[$slot] = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConnectionById($connectionID)
|
||||
{
|
||||
if (isset($this->pool[$connectionID])) {
|
||||
return $this->pool[$connectionID];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random connection from the pool.
|
||||
*
|
||||
* @return SingleConnectionInterface
|
||||
*/
|
||||
protected function getRandomConnection()
|
||||
{
|
||||
if ($this->pool) {
|
||||
return $this->pool[array_rand($this->pool)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently associates the connection instance to a new slot.
|
||||
* The connection is added to the connections pool if not yet included.
|
||||
*
|
||||
* @param SingleConnectionInterface $connection Connection instance.
|
||||
* @param int $slot Target slot index.
|
||||
*/
|
||||
protected function move(SingleConnectionInterface $connection, $slot)
|
||||
{
|
||||
@@ -304,53 +366,76 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying command hash strategy used to hash
|
||||
* commands by their keys.
|
||||
* Handles -ERR responses returned by Redis.
|
||||
*
|
||||
* @return CommandHashStrategyInterface
|
||||
*/
|
||||
public function getCommandHashStrategy()
|
||||
{
|
||||
return $this->strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator(array_values($this->pool));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles -ERR replies from Redis.
|
||||
*
|
||||
* @param CommandInterface $command Command that generated the -ERR reply.
|
||||
* @param ResponseErrorInterface $error Redis error reply object.
|
||||
* @param CommandInterface $command Command that generated the -ERR response.
|
||||
* @param ResponseErrorInterface $error Redis error response object.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function handleServerError(CommandInterface $command, ResponseErrorInterface $error)
|
||||
protected function onErrorResponse(CommandInterface $command, ResponseErrorInterface $error)
|
||||
{
|
||||
list($type, $details) = explode(' ', $error->getMessage(), 2);
|
||||
$details = explode(' ', $error->getMessage(), 2);
|
||||
|
||||
switch ($type) {
|
||||
switch ($details[0]) {
|
||||
case 'MOVED':
|
||||
return $this->onMovedResponse($command, $details[1]);
|
||||
|
||||
case 'ASK':
|
||||
return $this->onMoveRequest($command, $type, $details);
|
||||
return $this->onAskResponse($command, $details[1]);
|
||||
|
||||
default:
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles -MOVED responses by executing again the command against the node
|
||||
* indicated by the Redis response.
|
||||
*
|
||||
* @param CommandInterface $command Command that generated the -MOVED response.
|
||||
* @param string $details Parameters of the -MOVED response.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function onMovedResponse(CommandInterface $command, $details)
|
||||
{
|
||||
list($slot, $connectionID) = explode(' ', $details, 2);
|
||||
|
||||
if (!$connection = $this->getConnectionById($connectionID)) {
|
||||
$connection = $this->createConnection($connectionID);
|
||||
}
|
||||
|
||||
if ($this->askClusterNodes) {
|
||||
$this->askClusterNodes();
|
||||
}
|
||||
|
||||
$this->move($connection, $slot);
|
||||
$response = $this->executeCommand($command);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles -ASK responses by executing again the command against the node
|
||||
* indicated by the Redis response.
|
||||
*
|
||||
* @param CommandInterface $command Command that generated the -ASK response.
|
||||
* @param string $details Parameters of the -ASK response.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function onAskResponse(CommandInterface $command, $details)
|
||||
{
|
||||
list($slot, $connectionID) = explode(' ', $details, 2);
|
||||
|
||||
if (!$connection = $this->getConnectionById($connectionID)) {
|
||||
$connection = $this->createConnection($connectionID);
|
||||
}
|
||||
|
||||
$connection->executeCommand(RawCommand::create('ASKING'));
|
||||
$response = $connection->executeCommand($command);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -373,12 +458,74 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C
|
||||
public function executeCommand(CommandInterface $command)
|
||||
{
|
||||
$connection = $this->getConnection($command);
|
||||
$reply = $connection->executeCommand($command);
|
||||
$response = $connection->executeCommand($command);
|
||||
|
||||
if ($reply instanceof ResponseErrorInterface) {
|
||||
return $this->handleServerError($command, $reply);
|
||||
if ($response instanceof ResponseErrorInterface) {
|
||||
return $this->onErrorResponse($command, $response);
|
||||
}
|
||||
|
||||
return $reply;
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator(array_values($this->pool));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying hash strategy used to hash commands by their keys.
|
||||
*
|
||||
* @return CommandHashStrategyInterface
|
||||
*/
|
||||
public function getCommandHashStrategy()
|
||||
{
|
||||
return $this->strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables automatic fetching of the current slots map from one of the nodes
|
||||
* using the CLUSTER NODES command. This option is disabled by default but
|
||||
* asking the current slots map to Redis upon -MOVE responses may reduce
|
||||
* overhead by eliminating the trial-and-error nature of the node guessing
|
||||
* procedure, mostly when targeting many keys that would end up in a lot of
|
||||
* redirections.
|
||||
*
|
||||
* The slots map can still be manually fetched using the askClusterNodes()
|
||||
* method whether or not this option is enabled.
|
||||
*
|
||||
* @param bool $value Enable or disable the use of CLUSTER NODES.
|
||||
*/
|
||||
public function enableClusterNodes($value)
|
||||
{
|
||||
$this->askClusterNodes = (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default array of connection parameters to be applied when creating
|
||||
* new connection instances on the fly when they are not part of the initial
|
||||
* pool supplied upon cluster initialization.
|
||||
*
|
||||
* These parameters are not applied to connections added to the pool using
|
||||
* the add() method.
|
||||
*
|
||||
* @param array $parameters Array of connection parameters.
|
||||
*/
|
||||
public function setDefaultParameters(array $parameters)
|
||||
{
|
||||
$this->defaultParameters = array_merge(
|
||||
$this->defaultParameters,
|
||||
$parameters ?: array()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ use Predis\Iterator\MultiBulkResponseSimple;
|
||||
* - scheme: it can be either 'tcp' or 'unix'.
|
||||
* - host: hostname or IP address of the server.
|
||||
* - port: TCP port of the server.
|
||||
* - path: path of a UNIX domain socket when scheme is 'unix'.
|
||||
* - timeout: timeout to perform the connection.
|
||||
* - read_write_timeout: timeout of read / write operations.
|
||||
* - async_connect: performs the connection asynchronously.
|
||||
@@ -72,19 +73,21 @@ class StreamConnection extends AbstractConnection
|
||||
/**
|
||||
* Initializes a TCP stream resource.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @return resource
|
||||
*/
|
||||
private function tcpStreamInitializer(ConnectionParametersInterface $parameters)
|
||||
{
|
||||
$uri = "tcp://{$parameters->host}:{$parameters->port}/";
|
||||
$uri = "tcp://{$parameters->host}:{$parameters->port}";
|
||||
$flags = STREAM_CLIENT_CONNECT;
|
||||
|
||||
if (isset($parameters->async_connect) && $parameters->async_connect) {
|
||||
$flags |= STREAM_CLIENT_ASYNC_CONNECT;
|
||||
}
|
||||
|
||||
if (isset($parameters->persistent) && $parameters->persistent) {
|
||||
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||
$uri .= strpos($path = $parameters->path, '/') === 0 ? $path : "/$path";
|
||||
}
|
||||
|
||||
$resource = @stream_socket_client($uri, $errno, $errstr, $parameters->timeout, $flags);
|
||||
@@ -101,7 +104,7 @@ class StreamConnection extends AbstractConnection
|
||||
stream_set_timeout($resource, $timeoutSeconds, $timeoutUSeconds);
|
||||
}
|
||||
|
||||
if (isset($parameters->tcp_nodelay) && version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
if (isset($parameters->tcp_nodelay) && function_exists('socket_import_stream')) {
|
||||
$socket = socket_import_stream($resource);
|
||||
socket_set_option($socket, SOL_TCP, TCP_NODELAY, (int) $parameters->tcp_nodelay);
|
||||
}
|
||||
@@ -112,7 +115,7 @@ class StreamConnection extends AbstractConnection
|
||||
/**
|
||||
* Initializes a UNIX stream resource.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @return resource
|
||||
*/
|
||||
private function unixStreamInitializer(ConnectionParametersInterface $parameters)
|
||||
@@ -180,7 +183,7 @@ class StreamConnection extends AbstractConnection
|
||||
$socket = $this->getResource();
|
||||
|
||||
while (($length = strlen($buffer)) > 0) {
|
||||
$written = fwrite($socket, $buffer);
|
||||
$written = @fwrite($socket, $buffer);
|
||||
|
||||
if ($length === $written) {
|
||||
return;
|
||||
@@ -209,7 +212,7 @@ class StreamConnection extends AbstractConnection
|
||||
$payload = substr($chunk, 1, -2);
|
||||
|
||||
switch ($prefix) {
|
||||
case '+': // inline
|
||||
case '+':
|
||||
switch ($payload) {
|
||||
case 'OK':
|
||||
return true;
|
||||
@@ -221,7 +224,7 @@ class StreamConnection extends AbstractConnection
|
||||
return $payload;
|
||||
}
|
||||
|
||||
case '$': // bulk
|
||||
case '$':
|
||||
$size = (int) $payload;
|
||||
if ($size === -1) {
|
||||
return null;
|
||||
@@ -243,7 +246,7 @@ class StreamConnection extends AbstractConnection
|
||||
|
||||
return substr($bulkData, 0, -2);
|
||||
|
||||
case '*': // multi bulk
|
||||
case '*':
|
||||
$count = (int) $payload;
|
||||
|
||||
if ($count === -1) {
|
||||
@@ -261,10 +264,10 @@ class StreamConnection extends AbstractConnection
|
||||
|
||||
return $multibulk;
|
||||
|
||||
case ':': // integer
|
||||
case ':':
|
||||
return (int) $payload;
|
||||
|
||||
case '-': // error
|
||||
case '-':
|
||||
return new ResponseError($payload);
|
||||
|
||||
default:
|
||||
@@ -285,7 +288,7 @@ class StreamConnection extends AbstractConnection
|
||||
|
||||
$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandId}\r\n";
|
||||
|
||||
for ($i = 0; $i < $reqlen - 1; $i++) {
|
||||
for ($i = 0, $reqlen--; $i < $reqlen; $i++) {
|
||||
$argument = $arguments[$i];
|
||||
$arglen = strlen($argument);
|
||||
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
|
||||
|
||||
@@ -102,7 +102,7 @@ class WebdisConnection implements SingleConnectionInterface
|
||||
/**
|
||||
* Initializes cURL.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @return resource
|
||||
*/
|
||||
private function initializeCurl(ConnectionParametersInterface $parameters)
|
||||
@@ -128,7 +128,7 @@ class WebdisConnection implements SingleConnectionInterface
|
||||
/**
|
||||
* Initializes phpiredis' protocol reader.
|
||||
*
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @param ConnectionParametersInterface $parameters Parameters used to initialize the connection.
|
||||
* @return resource
|
||||
*/
|
||||
private function initializeReader(ConnectionParametersInterface $parameters)
|
||||
@@ -168,8 +168,8 @@ class WebdisConnection implements SingleConnectionInterface
|
||||
/**
|
||||
* Feeds phpredis' reader resource with the data read from the network.
|
||||
*
|
||||
* @param resource $resource Reader resource.
|
||||
* @param string $buffer Buffer with the reply read from the network.
|
||||
* @param resource $resource Reader resource.
|
||||
* @param string $buffer Buffer with the reply read from the network.
|
||||
* @return int
|
||||
*/
|
||||
protected function feedReader($resource, $buffer)
|
||||
@@ -206,7 +206,7 @@ class WebdisConnection implements SingleConnectionInterface
|
||||
/**
|
||||
* Checks if the specified command is supported by this connection class.
|
||||
*
|
||||
* @param CommandInterface $command The instance of a Redis command.
|
||||
* @param CommandInterface $command The instance of a Redis command.
|
||||
* @return string
|
||||
*/
|
||||
protected function getCommandId(CommandInterface $command)
|
||||
|
||||
@@ -22,7 +22,7 @@ interface ExecutableContextInterface
|
||||
/**
|
||||
* Starts the execution of the context.
|
||||
*
|
||||
* @param mixed $callable Optional callback for execution.
|
||||
* @param mixed $callable Optional callback for execution.
|
||||
* @return array
|
||||
*/
|
||||
public function execute($callable = null);
|
||||
|
||||
@@ -43,7 +43,7 @@ class Helpers
|
||||
* Normalizes the arguments array passed to a Redis command.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeArguments()
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function filterArrayArguments(Array $arguments)
|
||||
@@ -59,7 +59,7 @@ class Helpers
|
||||
* Normalizes the arguments array passed to a variadic Redis command.
|
||||
*
|
||||
* @deprecated Deprecated since v0.8.3 - moved in Predis\Command\AbstractCommand::normalizeVariadic()
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @param array $arguments Arguments for a command.
|
||||
* @return array
|
||||
*/
|
||||
public static function filterVariadicValues(Array $arguments)
|
||||
|
||||
@@ -96,5 +96,5 @@ abstract class MultiBulkResponse implements \Iterator, \Countable, ResponseObjec
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected abstract function getValue();
|
||||
abstract protected function getValue();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class MultiBulkResponseSimple extends MultiBulkResponse
|
||||
|
||||
/**
|
||||
* @param SingleConnectionInterface $connection Connection to Redis.
|
||||
* @param int $size Number of elements of the multibulk reply.
|
||||
* @param int $size Number of elements of the multibulk reply.
|
||||
*/
|
||||
public function __construct(SingleConnectionInterface $connection, $size)
|
||||
{
|
||||
@@ -49,8 +49,8 @@ class MultiBulkResponseSimple extends MultiBulkResponse
|
||||
* read from the connection by consuming the rest of the multibulk reply,
|
||||
* or simply by dropping the connection.
|
||||
*
|
||||
* @param Boolean $drop True to synchronize the client by dropping the connection.
|
||||
* False to synchronize the client by consuming the multibulk reply.
|
||||
* @param bool $drop True to synchronize the client by dropping the connection.
|
||||
* False to synchronize the client by consuming the multibulk reply.
|
||||
*/
|
||||
public function sync($drop = false)
|
||||
{
|
||||
|
||||
@@ -117,7 +117,7 @@ class MonitorContext implements \Iterator
|
||||
/**
|
||||
* Checks if the the context is still in a valid state to continue.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ class ClientCluster extends AbstractOption
|
||||
/**
|
||||
* Checks if the specified value is a valid instance of ClusterConnectionInterface.
|
||||
*
|
||||
* @param ClusterConnectionInterface $cluster Instance of a connection cluster.
|
||||
* @param ClusterConnectionInterface $cluster Instance of a connection cluster.
|
||||
* @return ClusterConnectionInterface
|
||||
*/
|
||||
protected function checkInstance($cluster)
|
||||
@@ -54,8 +54,8 @@ class ClientCluster extends AbstractOption
|
||||
/**
|
||||
* Returns an initializer for the specified FQN or type.
|
||||
*
|
||||
* @param string $fqnOrType Type of cluster or FQN of a class implementing ClusterConnectionInterface.
|
||||
* @param ClientOptionsInterface $options Instance of the client options.
|
||||
* @param string $fqnOrType Type of cluster or FQN of a class implementing ClusterConnectionInterface.
|
||||
* @param ClientOptionsInterface $options Instance of the client options.
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function getInitializer(ClientOptionsInterface $options, $fqnOrType)
|
||||
@@ -79,6 +79,7 @@ class ClientCluster extends AbstractOption
|
||||
if (is_string($fqnOrType) && !class_exists($fqnOrType)) {
|
||||
throw new \InvalidArgumentException("Class $fqnOrType does not exist");
|
||||
}
|
||||
|
||||
return function () use ($fqnOrType) {
|
||||
return new $fqnOrType();
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ class ClientConnectionFactory extends AbstractOption
|
||||
return $factory;
|
||||
}
|
||||
|
||||
if (@class_exists($value)) {
|
||||
if (is_string($value) && @class_exists($value)) {
|
||||
$factory = new $value();
|
||||
|
||||
if (!$factory instanceof ConnectionFactoryInterface) {
|
||||
|
||||
@@ -51,7 +51,7 @@ class ClientOptions implements ClientOptionsInterface
|
||||
/**
|
||||
* Initializes client options handlers.
|
||||
*
|
||||
* @param array $options List of client options values.
|
||||
* @param array $options List of client options values.
|
||||
* @return array
|
||||
*/
|
||||
protected function initialize(Array $options)
|
||||
@@ -75,8 +75,8 @@ class ClientOptions implements ClientOptionsInterface
|
||||
/**
|
||||
* Checks if the specified option is set.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @return Boolean
|
||||
* @param string $option Name of the option.
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($option)
|
||||
{
|
||||
@@ -86,7 +86,7 @@ class ClientOptions implements ClientOptionsInterface
|
||||
/**
|
||||
* Returns the value of the specified option.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @param string $option Name of the option.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($option)
|
||||
@@ -107,7 +107,7 @@ class ClientOptions implements ClientOptionsInterface
|
||||
/**
|
||||
* Returns the default value for the specified option.
|
||||
*
|
||||
* @param string|OptionInterface $option Name or instance of the option.
|
||||
* @param string|OptionInterface $option Name or instance of the option.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault($option)
|
||||
|
||||
@@ -24,7 +24,7 @@ class ClientReplication extends AbstractOption
|
||||
/**
|
||||
* Checks if the specified value is a valid instance of ReplicationConnectionInterface.
|
||||
*
|
||||
* @param ReplicationConnectionInterface $connection Instance of a replication connection.
|
||||
* @param ReplicationConnectionInterface $connection Instance of a replication connection.
|
||||
* @return ReplicationConnectionInterface
|
||||
*/
|
||||
protected function checkInstance($connection)
|
||||
|
||||
@@ -33,8 +33,8 @@ class CustomOption implements OptionInterface
|
||||
/**
|
||||
* Checks if the specified value in the options array is a callable object.
|
||||
*
|
||||
* @param array $options Array of options
|
||||
* @param string $key Target option.
|
||||
* @param array $options Array of options
|
||||
* @param string $key Target option.
|
||||
*/
|
||||
private function ensureCallable($options, $key)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,8 @@ interface OptionInterface
|
||||
/**
|
||||
* Filters (and optionally converts) the passed value.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @param ClientOptionsInterface $options Options container.
|
||||
* @param mixed $value Input value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function filter(ClientOptionsInterface $options, $value);
|
||||
@@ -29,16 +30,17 @@ interface OptionInterface
|
||||
/**
|
||||
* Returns a default value for the option.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @param ClientOptionsInterface $options Options container.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefault(ClientOptionsInterface $options);
|
||||
|
||||
/**
|
||||
* Filters a value and, if no value is specified, returns
|
||||
* the default one defined by the option.
|
||||
* Filters a value and, if no value is specified, returns the default one
|
||||
* defined by the option.
|
||||
*
|
||||
* @param mixed $value Input value.
|
||||
* @param ClientOptionsInterface $options Options container.
|
||||
* @param mixed $value Input value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __invoke(ClientOptionsInterface $options, $value);
|
||||
|
||||
@@ -100,8 +100,8 @@ class MultiExecExecutor implements PipelineExecutorInterface
|
||||
/**
|
||||
* Consumes an iterator response returned by EXEC.
|
||||
*
|
||||
* @param SplQueue $commands Pipelined commands
|
||||
* @param Iterator $responses Responses returned by EXEC.
|
||||
* @param SplQueue $commands Pipelined commands
|
||||
* @param Iterator $responses Responses returned by EXEC.
|
||||
* @return array
|
||||
*/
|
||||
protected function consumeIteratorResponse(SplQueue $commands, Iterator $responses)
|
||||
@@ -129,8 +129,8 @@ class MultiExecExecutor implements PipelineExecutorInterface
|
||||
/**
|
||||
* Consumes an array response returned by EXEC.
|
||||
*
|
||||
* @param SplQueue $commands Pipelined commands
|
||||
* @param Array $responses Responses returned by EXEC.
|
||||
* @param SplQueue $commands Pipelined commands
|
||||
* @param Array $responses Responses returned by EXEC.
|
||||
* @return array
|
||||
*/
|
||||
protected function consumeArrayResponse(SplQueue $commands, Array &$responses)
|
||||
|
||||
@@ -34,7 +34,7 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
private $running = false;
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param PipelineExecutorInterface $executor Pipeline executor instace.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, PipelineExecutorInterface $executor = null)
|
||||
@@ -48,7 +48,7 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
* Returns a pipeline executor depending on the kind of the underlying
|
||||
* connection and the passed options.
|
||||
*
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @return PipelineExecutorInterface
|
||||
*/
|
||||
protected function createExecutor(ClientInterface $client)
|
||||
@@ -65,9 +65,9 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
/**
|
||||
* Queues a command into the pipeline buffer.
|
||||
*
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return PipelineContext
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return $this
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
@@ -91,16 +91,19 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
* Queues a command instance into the pipeline buffer.
|
||||
*
|
||||
* @param CommandInterface $command Command to queue in the buffer.
|
||||
* @return $this
|
||||
*/
|
||||
public function executeCommand(CommandInterface $command)
|
||||
{
|
||||
$this->recordCommand($command);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes the buffer that holds the queued commands.
|
||||
*
|
||||
* @param Boolean $send Specifies if the commands in the buffer should be sent to Redis.
|
||||
* @param bool $send Specifies if the commands in the buffer should be sent to Redis.
|
||||
* @return PipelineContext
|
||||
*/
|
||||
public function flushPipeline($send = true)
|
||||
@@ -119,8 +122,8 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
/**
|
||||
* Marks the running status of the pipeline.
|
||||
*
|
||||
* @param Boolean $bool True if the pipeline is running.
|
||||
* False if the pipeline is not running.
|
||||
* @param bool $bool True if the pipeline is running.
|
||||
* False if the pipeline is not running.
|
||||
*/
|
||||
private function setRunning($bool)
|
||||
{
|
||||
@@ -134,7 +137,7 @@ class PipelineContext implements BasicClientInterface, ExecutableContextInterfac
|
||||
/**
|
||||
* Handles the actual execution of the whole pipeline.
|
||||
*
|
||||
* @param mixed $callable Optional callback for execution.
|
||||
* @param mixed $callable Optional callback for execution.
|
||||
* @return array
|
||||
*/
|
||||
public function execute($callable = null)
|
||||
|
||||
@@ -25,8 +25,8 @@ interface PipelineExecutorInterface
|
||||
/**
|
||||
* Writes a list of commands to the network and reads back their replies.
|
||||
*
|
||||
* @param ConnectionInterface $connection Connection to Redis.
|
||||
* @param SplQueue $commands Commands queued for execution.
|
||||
* @param ConnectionInterface $connection Connection to Redis.
|
||||
* @param SplQueue $commands Commands queued for execution.
|
||||
* @return array
|
||||
*/
|
||||
public function execute(ConnectionInterface $connection, SplQueue $commands);
|
||||
|
||||
@@ -56,9 +56,9 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
/**
|
||||
* Handles a response object.
|
||||
*
|
||||
* @param ConnectionInterface $connection
|
||||
* @param CommandInterface $command
|
||||
* @param ResponseObjectInterface $response
|
||||
* @param ConnectionInterface $connection
|
||||
* @param CommandInterface $command
|
||||
* @param ResponseObjectInterface $response
|
||||
* @return mixed
|
||||
*/
|
||||
protected function onResponseObject(ConnectionInterface $connection, CommandInterface $command, ResponseObjectInterface $response)
|
||||
@@ -77,8 +77,9 @@ class StandardExecutor implements PipelineExecutorInterface
|
||||
/**
|
||||
* Handles -ERR responses returned by Redis.
|
||||
*
|
||||
* @param ConnectionInterface $connection The connection that returned the error.
|
||||
* @param ResponseErrorInterface $response The error response instance.
|
||||
* @param ConnectionInterface $connection The connection that returned the error.
|
||||
* @param ResponseErrorInterface $response The error response instance.
|
||||
* @return ResponseErrorInterface
|
||||
*/
|
||||
protected function onResponseError(ConnectionInterface $connection, ResponseErrorInterface $response)
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected abstract function getSupportedCommands();
|
||||
abstract protected function getSupportedCommands();
|
||||
|
||||
/**
|
||||
* Returns the default server profile.
|
||||
@@ -78,7 +78,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
'2.4' => 'Predis\Profile\ServerVersion24',
|
||||
'2.6' => 'Predis\Profile\ServerVersion26',
|
||||
'2.8' => 'Predis\Profile\ServerVersion28',
|
||||
'default' => 'Predis\Profile\ServerVersion26',
|
||||
'default' => 'Predis\Profile\ServerVersion28',
|
||||
'dev' => 'Predis\Profile\ServerVersionNext',
|
||||
);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
/**
|
||||
* Registers a new server profile.
|
||||
*
|
||||
* @param string $alias Profile version or alias.
|
||||
* @param string $alias Profile version or alias.
|
||||
* @param string $profileClass FQN of a class implementing Predis\Profile\ServerProfileInterface.
|
||||
*/
|
||||
public static function define($alias, $profileClass)
|
||||
@@ -107,7 +107,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
/**
|
||||
* Returns the specified server profile.
|
||||
*
|
||||
* @param string $version Profile version or alias.
|
||||
* @param string $version Profile version or alias.
|
||||
* @return ServerProfileInterface
|
||||
*/
|
||||
public static function get($version)
|
||||
@@ -151,7 +151,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
* Returns the FQN of the class that represent the specified command ID
|
||||
* registered in the current server profile.
|
||||
*
|
||||
* @param string $command Command ID.
|
||||
* @param string $command Command ID.
|
||||
* @return string
|
||||
*/
|
||||
public function getCommandClass($command)
|
||||
@@ -186,7 +186,7 @@ abstract class ServerProfile implements ServerProfileInterface, CommandProcessin
|
||||
/**
|
||||
* Defines a new commands in the server profile.
|
||||
*
|
||||
* @param string $alias Command ID.
|
||||
* @param string $alias Command ID.
|
||||
* @param string $command FQN of a class implementing Predis\Command\CommandInterface.
|
||||
*/
|
||||
public function defineCommand($alias, $command)
|
||||
|
||||
@@ -32,15 +32,15 @@ interface ServerProfileInterface
|
||||
/**
|
||||
* Checks if the profile supports the specified command.
|
||||
*
|
||||
* @param string $command Command ID.
|
||||
* @return Boolean
|
||||
* @param string $command Command ID.
|
||||
* @return bool
|
||||
*/
|
||||
public function supportsCommand($command);
|
||||
|
||||
/**
|
||||
* Checks if the profile supports the specified list of commands.
|
||||
*
|
||||
* @param array $commands List of command IDs.
|
||||
* @param array $commands List of command IDs.
|
||||
* @return string
|
||||
*/
|
||||
public function supportsCommands(Array $commands);
|
||||
@@ -48,8 +48,8 @@ interface ServerProfileInterface
|
||||
/**
|
||||
* Creates a new command instance.
|
||||
*
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @param string $method Command ID.
|
||||
* @param array $arguments Arguments for the command.
|
||||
* @return CommandInterface
|
||||
*/
|
||||
public function createCommand($method, $arguments = array());
|
||||
|
||||
@@ -121,7 +121,6 @@ class ServerVersion20 extends ServerProfile
|
||||
'shutdown' => 'Predis\Command\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
|
||||
@@ -121,7 +121,6 @@ class ServerVersion22 extends ServerProfile
|
||||
'shutdown' => 'Predis\Command\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
@@ -170,7 +169,6 @@ class ServerVersion22 extends ServerProfile
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Command\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
|
||||
@@ -121,7 +121,6 @@ class ServerVersion24 extends ServerProfile
|
||||
'shutdown' => 'Predis\Command\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
@@ -170,7 +169,6 @@ class ServerVersion24 extends ServerProfile
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Command\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
@@ -200,7 +198,6 @@ class ServerVersion24 extends ServerProfile
|
||||
'object' => 'Predis\Command\ServerObject',
|
||||
'slowlog' => 'Predis\Command\ServerSlowlog',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.4 ---------------- */
|
||||
|
||||
/* remote server control commands */
|
||||
|
||||
@@ -111,7 +111,7 @@ class ServerVersion26 extends ServerProfile
|
||||
'quit' => 'Predis\Command\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Command\ServerInfo',
|
||||
'info' => 'Predis\Command\ServerInfoV26x',
|
||||
'slaveof' => 'Predis\Command\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Command\ServerMonitor',
|
||||
'dbsize' => 'Predis\Command\ServerDatabaseSize',
|
||||
@@ -123,7 +123,6 @@ class ServerVersion26 extends ServerProfile
|
||||
'shutdown' => 'Predis\Command\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
@@ -172,7 +171,6 @@ class ServerVersion26 extends ServerProfile
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Command\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
@@ -202,13 +200,11 @@ class ServerVersion26 extends ServerProfile
|
||||
'object' => 'Predis\Command\ServerObject',
|
||||
'slowlog' => 'Predis\Command\ServerSlowlog',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.4 ---------------- */
|
||||
|
||||
/* remote server control commands */
|
||||
'client' => 'Predis\Command\ServerClient',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.6 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
@@ -231,7 +227,6 @@ class ServerVersion26 extends ServerProfile
|
||||
'script' => 'Predis\Command\ServerScript',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Command\ServerInfoV26x',
|
||||
'time' => 'Predis\Command\ServerTime',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ class ServerVersion28 extends ServerProfile
|
||||
'quit' => 'Predis\Command\ConnectionQuit',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Command\ServerInfo',
|
||||
'info' => 'Predis\Command\ServerInfoV26x',
|
||||
'slaveof' => 'Predis\Command\ServerSlaveOf',
|
||||
'monitor' => 'Predis\Command\ServerMonitor',
|
||||
'dbsize' => 'Predis\Command\ServerDatabaseSize',
|
||||
@@ -123,7 +123,6 @@ class ServerVersion28 extends ServerProfile
|
||||
'shutdown' => 'Predis\Command\ServerShutdown',
|
||||
'bgrewriteaof' => 'Predis\Command\ServerBackgroundRewriteAOF',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
|
||||
/* commands operating on string values */
|
||||
@@ -172,7 +171,6 @@ class ServerVersion28 extends ServerProfile
|
||||
/* remote server control commands */
|
||||
'config' => 'Predis\Command\ServerConfig',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
@@ -202,13 +200,11 @@ class ServerVersion28 extends ServerProfile
|
||||
'object' => 'Predis\Command\ServerObject',
|
||||
'slowlog' => 'Predis\Command\ServerSlowlog',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.4 ---------------- */
|
||||
|
||||
/* remote server control commands */
|
||||
'client' => 'Predis\Command\ServerClient',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.6 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
@@ -231,10 +227,8 @@ class ServerVersion28 extends ServerProfile
|
||||
'script' => 'Predis\Command\ServerScript',
|
||||
|
||||
/* remote server control commands */
|
||||
'info' => 'Predis\Command\ServerInfoV26x',
|
||||
'time' => 'Predis\Command\ServerTime',
|
||||
|
||||
|
||||
/* ---------------- Redis 2.8 ---------------- */
|
||||
|
||||
/* commands operating on the key space */
|
||||
@@ -245,9 +239,17 @@ class ServerVersion28 extends ServerProfile
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zscan' => 'Predis\Command\ZSetScan',
|
||||
'zlexcount' => 'Predis\Command\ZSetLexCount',
|
||||
'zrangebylex' => 'Predis\Command\ZSetRangeByLex',
|
||||
'zremrangebylex' => 'Predis\Command\ZSetRemoveRangeByLex',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hscan' => 'Predis\Command\HashScan',
|
||||
|
||||
/* commands operating on HyperLogLog */
|
||||
'pfadd' => 'Predis\Command\HyperLogLogAdd',
|
||||
'pfcount' => 'Predis\Command\HyperLogLogCount',
|
||||
'pfmerge' => 'Predis\Command\HyperLogLogMerge',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ interface CommandSerializerInterface
|
||||
/**
|
||||
* Serializes a Redis command.
|
||||
*
|
||||
* @param CommandInterface $command Redis command.
|
||||
* @param CommandInterface $command Redis command.
|
||||
* @return string
|
||||
*/
|
||||
public function serialize(CommandInterface $command);
|
||||
|
||||
@@ -26,7 +26,7 @@ interface ProtocolInterface extends ResponseReaderInterface
|
||||
* Writes a Redis command on the specified connection.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param CommandInterface $command Redis command.
|
||||
* @param CommandInterface $command Redis command.
|
||||
*/
|
||||
public function write(ComposableConnectionInterface $connection, CommandInterface $command);
|
||||
|
||||
@@ -34,7 +34,7 @@ interface ProtocolInterface extends ResponseReaderInterface
|
||||
* Sets the options for the protocol processor.
|
||||
*
|
||||
* @param string $option Name of the option.
|
||||
* @param mixed $value Value of the option.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
public function setOption($option, $value);
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ interface ResponseHandlerInterface
|
||||
* Parses a type of reply returned by Redis and reads more data from the
|
||||
* connection if needed.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $payload Initial payload of the reply.
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $payload Initial payload of the reply.
|
||||
* @return mixed
|
||||
*/
|
||||
function handle(ComposableConnectionInterface $connection, $payload);
|
||||
public function handle(ComposableConnectionInterface $connection, $payload);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ interface ResponseReaderInterface
|
||||
/**
|
||||
* Reads replies from a connection to Redis and deserializes them.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @return mixed
|
||||
*/
|
||||
public function read(ComposableConnectionInterface $connection);
|
||||
|
||||
@@ -28,8 +28,8 @@ class ResponseBulkHandler implements ResponseHandlerInterface
|
||||
/**
|
||||
* Handles a bulk reply returned by Redis.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $lengthString Bytes size of the bulk reply.
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $lengthString Bytes size of the bulk reply.
|
||||
* @return string
|
||||
*/
|
||||
public function handle(ComposableConnectionInterface $connection, $lengthString)
|
||||
|
||||
@@ -28,8 +28,8 @@ class ResponseIntegerHandler implements ResponseHandlerInterface
|
||||
/**
|
||||
* Handles an integer reply returned by Redis.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $number String representation of an integer.
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $number String representation of an integer.
|
||||
* @return int
|
||||
*/
|
||||
public function handle(ComposableConnectionInterface $connection, $number)
|
||||
|
||||
@@ -28,8 +28,8 @@ class ResponseMultiBulkHandler implements ResponseHandlerInterface
|
||||
/**
|
||||
* Handles a multi-bulk reply returned by Redis.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $lengthString Number of items in the multi-bulk reply.
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $lengthString Number of items in the multi-bulk reply.
|
||||
* @return array
|
||||
*/
|
||||
public function handle(ComposableConnectionInterface $connection, $lengthString)
|
||||
|
||||
@@ -29,8 +29,8 @@ class ResponseMultiBulkStreamHandler implements ResponseHandlerInterface
|
||||
/**
|
||||
* Handles a multi-bulk reply returned by Redis in a streamable fashion.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $lengthString Number of items in the multi-bulk reply.
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis.
|
||||
* @param string $lengthString Number of items in the multi-bulk reply.
|
||||
* @return MultiBulkResponseSimple
|
||||
*/
|
||||
public function handle(ComposableConnectionInterface $connection, $lengthString)
|
||||
|
||||
@@ -36,7 +36,7 @@ class TextCommandSerializer implements CommandSerializerInterface
|
||||
|
||||
$buffer = "*{$reqlen}\r\n\${$cmdlen}\r\n{$commandId}\r\n";
|
||||
|
||||
for ($i = 0; $i < $reqlen - 1; $i++) {
|
||||
for ($i = 0, $reqlen--; $i < $reqlen; $i++) {
|
||||
$argument = $arguments[$i];
|
||||
$arglen = strlen($argument);
|
||||
$buffer .= "\${$arglen}\r\n{$argument}\r\n";
|
||||
|
||||
@@ -72,7 +72,7 @@ class TextProtocol implements ProtocolInterface
|
||||
$payload = substr($chunk, 1);
|
||||
|
||||
switch ($prefix) {
|
||||
case '+': // inline
|
||||
case '+':
|
||||
switch ($payload) {
|
||||
case 'OK':
|
||||
return true;
|
||||
@@ -84,14 +84,15 @@ class TextProtocol implements ProtocolInterface
|
||||
return $payload;
|
||||
}
|
||||
|
||||
case '$': // bulk
|
||||
case '$':
|
||||
$size = (int) $payload;
|
||||
if ($size === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return substr($connection->readBytes($size + 2), 0, -2);
|
||||
|
||||
case '*': // multi bulk
|
||||
case '*':
|
||||
$count = (int) $payload;
|
||||
|
||||
if ($count === -1) {
|
||||
@@ -109,10 +110,10 @@ class TextProtocol implements ProtocolInterface
|
||||
|
||||
return $multibulk;
|
||||
|
||||
case ':': // integer
|
||||
case ':':
|
||||
return (int) $payload;
|
||||
|
||||
case '-': // error
|
||||
case '-':
|
||||
return new ResponseError($payload);
|
||||
|
||||
default:
|
||||
|
||||
@@ -55,7 +55,7 @@ class TextResponseReader implements ResponseReaderInterface
|
||||
* Sets a response handler for a certain prefix that identifies a type of
|
||||
* reply that can be returned by Redis.
|
||||
*
|
||||
* @param string $prefix Identifier for a type of reply.
|
||||
* @param string $prefix Identifier for a type of reply.
|
||||
* @param ResponseHandlerInterface $handler Response handler for the reply.
|
||||
*/
|
||||
public function setHandler($prefix, ResponseHandlerInterface $handler)
|
||||
@@ -67,7 +67,7 @@ class TextResponseReader implements ResponseReaderInterface
|
||||
* Returns the response handler associated to a certain type of reply that
|
||||
* can be returned by Redis.
|
||||
*
|
||||
* @param string $prefix Identifier for a type of reply.
|
||||
* @param string $prefix Identifier for a type of reply.
|
||||
* @return ResponseHandlerInterface
|
||||
*/
|
||||
public function getHandler($prefix)
|
||||
@@ -104,7 +104,7 @@ class TextResponseReader implements ResponseReaderInterface
|
||||
* reply from a connection to Redis.
|
||||
*
|
||||
* @param ComposableConnectionInterface $connection Connection to Redis that generated the error.
|
||||
* @param string $message Error message.
|
||||
* @param string $message Error message.
|
||||
*/
|
||||
private function protocolError(ComposableConnectionInterface $connection, $message)
|
||||
{
|
||||
|
||||
@@ -43,8 +43,8 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Checks if the specified flag is valid in the state of the context.
|
||||
*
|
||||
* @param int $value Flag.
|
||||
* @return Boolean
|
||||
* @param int $value Flag.
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFlagSet($value)
|
||||
{
|
||||
@@ -54,9 +54,9 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Subscribes to the specified channels.
|
||||
*
|
||||
* @param mixed $arg,... One or more channel names.
|
||||
* @param mixed $channel,... One or more channel names.
|
||||
*/
|
||||
public function subscribe(/* arguments */)
|
||||
public function subscribe($channel /*, ... */)
|
||||
{
|
||||
$this->writeCommand(self::SUBSCRIBE, func_get_args());
|
||||
$this->statusFlags |= self::STATUS_SUBSCRIBED;
|
||||
@@ -65,9 +65,9 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Unsubscribes from the specified channels.
|
||||
*
|
||||
* @param mixed $arg,... One or more channel names.
|
||||
* @param string ... One or more channel names.
|
||||
*/
|
||||
public function unsubscribe(/* arguments */)
|
||||
public function unsubscribe(/* ... */)
|
||||
{
|
||||
$this->writeCommand(self::UNSUBSCRIBE, func_get_args());
|
||||
}
|
||||
@@ -75,9 +75,9 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Subscribes to the specified channels using a pattern.
|
||||
*
|
||||
* @param mixed $arg,... One or more channel name patterns.
|
||||
* @param mixed $pattern,... One or more channel name patterns.
|
||||
*/
|
||||
public function psubscribe(/* arguments */)
|
||||
public function psubscribe($pattern /* ... */)
|
||||
{
|
||||
$this->writeCommand(self::PSUBSCRIBE, func_get_args());
|
||||
$this->statusFlags |= self::STATUS_PSUBSCRIBED;
|
||||
@@ -86,9 +86,9 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Unsubscribes from the specified channels using a pattern.
|
||||
*
|
||||
* @param mixed $arg,... One or more channel name patterns.
|
||||
* @param string ... One or more channel name patterns.
|
||||
*/
|
||||
public function punsubscribe(/* arguments */)
|
||||
public function punsubscribe(/* ... */)
|
||||
{
|
||||
$this->writeCommand(self::PUNSUBSCRIBE, func_get_args());
|
||||
}
|
||||
@@ -98,8 +98,8 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
* Optionally, the context can be forcefully closed by dropping the
|
||||
* underlying connection.
|
||||
*
|
||||
* @param Boolean $force Forcefully close the context by closing the connection.
|
||||
* @return Boolean Returns false if there are no pending messages.
|
||||
* @param bool $force Forcefully close the context by closing the connection.
|
||||
* @return bool Returns false if there are no pending messages.
|
||||
*/
|
||||
public function closeContext($force = false)
|
||||
{
|
||||
@@ -125,15 +125,15 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Closes the underlying connection on forced disconnection.
|
||||
*/
|
||||
protected abstract function disconnect();
|
||||
abstract protected function disconnect();
|
||||
|
||||
/**
|
||||
* Writes a Redis command on the underlying connection.
|
||||
*
|
||||
* @param string $method ID of the command.
|
||||
* @param array $arguments List of arguments.
|
||||
* @param string $method ID of the command.
|
||||
* @param array $arguments List of arguments.
|
||||
*/
|
||||
protected abstract function writeCommand($method, $arguments);
|
||||
abstract protected function writeCommand($method, $arguments);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -177,7 +177,7 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
/**
|
||||
* Checks if the the context is still in a valid state to continue.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
@@ -202,5 +202,5 @@ abstract class AbstractPubSubContext implements \Iterator
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected abstract function getValue();
|
||||
abstract protected function getValue();
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class DispatcherLoop
|
||||
/**
|
||||
* Binds a callback to a channel.
|
||||
*
|
||||
* @param string $channel Channel name.
|
||||
* @param string $channel Channel name.
|
||||
* @param Callable $callback A callback.
|
||||
*/
|
||||
public function attachCallback($channel, $callback)
|
||||
@@ -137,7 +137,7 @@ class DispatcherLoop
|
||||
if (isset($this->callbacks[$message->channel])) {
|
||||
$callback = $this->callbacks[$message->channel];
|
||||
call_user_func($callback, $message->payload);
|
||||
} else if (isset($this->defaultCallback)) {
|
||||
} elseif (isset($this->defaultCallback)) {
|
||||
$callback = $this->defaultCallback;
|
||||
call_user_func($callback, $message);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ class PubSubContext extends AbstractPubSubContext
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param array $options Options for the context initialization.
|
||||
* @param ClientInterface $client Client instance used by the context.
|
||||
* @param array $options Options for the context initialization.
|
||||
*/
|
||||
public function __construct(ClientInterface $client, Array $options = null)
|
||||
{
|
||||
@@ -115,6 +115,8 @@ class PubSubContext extends AbstractPubSubContext
|
||||
if ($response[2] === 0) {
|
||||
$this->invalidate();
|
||||
}
|
||||
// The missing break here is intentional as we must process
|
||||
// subscriptions and unsubscriptions as standard messages.
|
||||
|
||||
case self::MESSAGE:
|
||||
return (object) array(
|
||||
|
||||
@@ -39,8 +39,8 @@ class ReplicationStrategy
|
||||
* Returns if the specified command performs a read-only operation
|
||||
* against a key stored on Redis.
|
||||
*
|
||||
* @param CommandInterface $command Instance of Redis command.
|
||||
* @return Boolean
|
||||
* @param CommandInterface $command Instance of Redis command.
|
||||
* @return bool
|
||||
*/
|
||||
public function isReadOperation(CommandInterface $command)
|
||||
{
|
||||
@@ -75,8 +75,8 @@ class ReplicationStrategy
|
||||
* Returns if the specified command is disallowed in a master/slave
|
||||
* replication context.
|
||||
*
|
||||
* @param CommandInterface $command Instance of Redis command.
|
||||
* @return Boolean
|
||||
* @param CommandInterface $command Instance of Redis command.
|
||||
* @return bool
|
||||
*/
|
||||
public function isDisallowedOperation(CommandInterface $command)
|
||||
{
|
||||
@@ -87,12 +87,13 @@ class ReplicationStrategy
|
||||
* Checks if a SORT command is a readable operation by parsing the arguments
|
||||
* array of the specified commad instance.
|
||||
*
|
||||
* @param CommandInterface $command Instance of Redis command.
|
||||
* @return Boolean
|
||||
* @param CommandInterface $command Instance of Redis command.
|
||||
* @return bool
|
||||
*/
|
||||
protected function isSortReadOnly(CommandInterface $command)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
|
||||
return ($c = count($arguments)) === 1 ? true : $arguments[$c - 2] !== 'STORE';
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ class ReplicationStrategy
|
||||
* instance of a command performs write operations or not.
|
||||
*
|
||||
* @param string $commandID ID of the command.
|
||||
* @param mixed $readonly A boolean or a callable object.
|
||||
* @param mixed $readonly A boolean or a callable object.
|
||||
*/
|
||||
public function setCommandReadOnly($commandID, $readonly = true)
|
||||
{
|
||||
@@ -123,8 +124,8 @@ class ReplicationStrategy
|
||||
* if the passed instance of EVAL or EVALSHA performs write operations or
|
||||
* not.
|
||||
*
|
||||
* @param string $script Body of the Lua script.
|
||||
* @param mixed $readonly A boolean or a callable object.
|
||||
* @param string $script Body of the Lua script.
|
||||
* @param mixed $readonly A boolean or a callable object.
|
||||
*/
|
||||
public function setScriptReadOnly($script, $readonly = true)
|
||||
{
|
||||
@@ -200,6 +201,8 @@ class ReplicationStrategy
|
||||
'ZRANK' => true,
|
||||
'ZREVRANK' => true,
|
||||
'ZSCAN' => true,
|
||||
'ZLEXCOUNT' => true,
|
||||
'ZRANGEBYLEX' => true,
|
||||
'HGET' => true,
|
||||
'HMGET' => true,
|
||||
'HEXISTS' => true,
|
||||
@@ -216,6 +219,7 @@ class ReplicationStrategy
|
||||
'OBJECT' => true,
|
||||
'BITCOUNT' => true,
|
||||
'TIME' => true,
|
||||
'PFCOUNT' => true,
|
||||
'SORT' => array($this, 'isSortReadOnly'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class ResponseError implements ResponseErrorInterface
|
||||
public function getErrorType()
|
||||
{
|
||||
list($errorType, ) = explode(' ', $this->getMessage(), 2);
|
||||
|
||||
return $errorType;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user