In this tutorial, we are going to try out a Redis client library for PHP. Unlike the Node.js client we used in the previous tutorials, the chosen PHP client library is synchronous and do not require a callback function.
We are going to use a client called Predis. The PHP version for all examples is 5.4. To install Predis we will use the PHP Composer.
Create a file called composer.json in the tutorial5 folder with the following content:
1 2 3 4 5 6 |
{ "name": "tutorial5", "require": { "predis/predis": "~1.0" } } |
Then inside the tutorial5 folder run Composer via composer update
. This command will install the Predis library.
Basic commands
Each executed command via Predis returns a value synchronously. Here is the sample code for some basic functions.
Create a file called index.php with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
require 'vendor/autoload.php'; Predis\Autoloader::register(); $client = new Predis\Client(['host' => '127.0.0.1', 'port' => 6379], ['prefix' => 'php:']); //simple key-value assignments $client->set("str:my_key", "Hello"); $client->incr("str:counter"); var_dump($client->mget(["str:my_key", "str:counter"])); //lists $client->rpush("list:my_list", "value1", "value2"); var_dump($client->lpop("list:my_list")); //hashes $client->hset("hash:tutorial", "title", "tutorial5"); var_dump($client->hgetall("hash:tutorial")); //sets $client->sadd("set:users", "user1", "user2"); var_dump($client->smembers("set:users")); //sorted sets $client->zadd("events", 2011, "event1"); $client->zadd("events", 2012, "event2"); var_dump($client->zrange("events", 0, -1, "withscores")); |
Then inside the tutorial folder run a PHP local server via php -S localhost:8080
. Now open http://localhost:8080 in your browser. You should see the following:
Blocking commands
There are 3 connection-blocking List commands: BRPOP, BLPOP, and BRPOPLPUSH. In the Node.js client, these commands expect a callback. In Predis, they don’t expect callbacks.
The BRPOP and BLPOP commands expect a list of keys and a timeout. BRPOPLPUSH expects a source key, a destination key, and a timeout. The timeout default value is zero. If the timeout is zero, the call will hang until an item is found. Redis client is blocked until there is at least one element in the List or until the timeout has been exceeded.
BRPOP: Blocking version of RPOP. An element is popped from the tail of the first List that is not empty.
BLPOP: Blocking version of LPOP. An element is popped from the head of the first List that is not empty.
BRPOPLPUSH: An element is popped from the tail of the source key and inserted at the head of the destination key.
Now modify the index.php
file this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
require 'vendor/autoload.php'; Predis\Autoloader::register(); $client = new Predis\Client(['host' => '127.0.0.1', 'port' => 6379], ['prefix' => 'php:']); $client->lpush("queue", "first"); $client->lpush("queue", "second"); var_dump($client->blpop(['queue'], 0)); var_dump($client->brpop(['queue'], 0)); $client->rpush("source", "message"); var_dump($client->brpoplpush('source','queue:destination', 0)); |
Run this code. You should see the following output:
Pipelines
There 2 ways to work with pipelines in Predis:
1. A client executes a pipeline inside an anonymous function(similar to callbacks in Node.js, but not asynchronous).
2. A client returns a pipeline instance with the ability to chain commands.
Modify the index.php
file this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
require 'vendor/autoload.php'; Predis\Autoloader::register(); $client = new Predis\Client(['host' => '127.0.0.1', 'port' => 6379], ['prefix' => 'php:']); //fluent interface $res1 = $client->pipeline() ->sadd('countries', 'USA!') ->sadd('countries', 'Argentina!') ->sadd('countries', 'Brazil!') ->sadd('countries', 'Scotland!') ->smembers('countries') ->execute(); var_dump($res1); //anonymous function $res2 = $client->pipeline(function($pipe){ $pipe->scard('countries'); $pipe->smembers('countries'); }); var_dump($res2); |
You should see the following:
Transactions
Predis provides an interface based on MULTI and EXEC with the ability to chain commands.
Modify the index.php
file this way:
1 2 3 4 5 6 7 8 9 10 11 |
require 'vendor/autoload.php'; Predis\Autoloader::register(); $client = new Predis\Client(['host' => '127.0.0.1', 'port' => 6379], ['prefix' => 'php:']); $res1 = $client->transaction() ->set('key', 'value') ->incr('key:counter') ->get('key') ->execute(); var_dump($res1); |
Output:
Lua scripting
Predis provides a higher level abstraction to register commands as if they were native Redis commands. Internally, Predis uses the EVALSHA command. EVAL is used as a fallback if needed.
You need to create a PHP class that extends Predis\Command\ScriptCommand and implements 2 methods:
1. getKeyCount: Returns the number of arguments that should be considered as keys.
2. getScript: Returns the body of a Lua code.
In the following code, we define a class called MultiplyValue, where we create a multiply command. It will obtain the value of a key, multiply it by the argument, and update the key with the new value.
Modify the index.php
file this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
require 'vendor/autoload.php'; Predis\Autoloader::register(); $client = new Predis\Client(['host' => '127.0.0.1', 'port' => 6379], ['prefix' => 'php:']); class MultiplyValue extends Predis\Command\ScriptCommand { public function getKeysCount(){ return 1; } public function getScript(){ $lua = " local value = redis.call('GET', KEYS[1]) value = tonumber(value) local newvalue = value * ARGV[1] redis.call('SET', KEYS[1], newvalue) return newvalue "; return $lua; } } //register the new command $client->getProfile()->defineCommand('multiply', 'MultiplyValue'); $client->set("number", 4); //recieves existing keu and the multiplication factor var_dump($client->multiply("number", 2)); |
You should see the following output:
That’s all for today.