Predis: Predis not Serializing Objects

Created on 19 May 2011  ·  6Comments  ·  Source: predis/predis

It appears that this fails:

// Set Array
$redis->set( 'key', array(1,2,3) );

This is unanticipated with such a complete library. Where is the best place to put an object/array serializer for all Reids Commands?

documentation

Most helpful comment

This is an intended behaviour: Predis does not (and will not ever) handle any kind of serialization, it is completely up to developers how to serialize or deserialize values passed or stored in Redis. Behind the scenes of your example, the value passed to SET is casted to a string (string) array(1,2,3) which leads to the string value Array.

If you really want to handle (de)serialization for certain operations in a transparent way for the application's code, you should rely on Predis' extensibility and define your own commands like in the following example (I'm using json as a serialization format, but you can choose anything that best fits your application):

<?php

require 'autoload.php';

class StringSetJson
    extends Predis\Commands\StringSet {

    protected function filterArguments(Array $arguments) {
        $arguments[1] = json_encode($arguments[1]);
        return $arguments;
    }
}

class StringGetJson
    extends Predis\Commands\StringGet {

    public function parseResponse($data) {
        return json_decode($data);
    }
}

$client = new Predis\Client();

$profile = $client->getProfile();
// If you want, you can override SET or GET just like any other command, but I 
// think it's better to use different names for your serialization-aware commands:
$profile->defineCommand('jsonset', 'StringSetJson');
$profile->defineCommand('jsonget', 'StringGetJson');

$client->jsonset("json_key", array(1,2,3,4));
$value = $client->jsonget("json_key");

In this way you have complete control on which kind of serialization strategy to use (e.g. _Igbinary_) and how it should work depending on the data. It is probably worth to add this in the FAQ file and the new documentation that will be prepared once Predis v0.7 is released.

All 6 comments

Rather the problem sits on reading with a GET command:

// Get Array
$data = $redis->get('key');

Recommendations?

This is an intended behaviour: Predis does not (and will not ever) handle any kind of serialization, it is completely up to developers how to serialize or deserialize values passed or stored in Redis. Behind the scenes of your example, the value passed to SET is casted to a string (string) array(1,2,3) which leads to the string value Array.

If you really want to handle (de)serialization for certain operations in a transparent way for the application's code, you should rely on Predis' extensibility and define your own commands like in the following example (I'm using json as a serialization format, but you can choose anything that best fits your application):

<?php

require 'autoload.php';

class StringSetJson
    extends Predis\Commands\StringSet {

    protected function filterArguments(Array $arguments) {
        $arguments[1] = json_encode($arguments[1]);
        return $arguments;
    }
}

class StringGetJson
    extends Predis\Commands\StringGet {

    public function parseResponse($data) {
        return json_decode($data);
    }
}

$client = new Predis\Client();

$profile = $client->getProfile();
// If you want, you can override SET or GET just like any other command, but I 
// think it's better to use different names for your serialization-aware commands:
$profile->defineCommand('jsonset', 'StringSetJson');
$profile->defineCommand('jsonget', 'StringGetJson');

$client->jsonset("json_key", array(1,2,3,4));
$value = $client->jsonget("json_key");

In this way you have complete control on which kind of serialization strategy to use (e.g. _Igbinary_) and how it should work depending on the data. It is probably worth to add this in the FAQ file and the new documentation that will be prepared once Predis v0.7 is released.

nrk,

Thank you for helping. This is disappointing since Memcache Clients support serialization automatically. PHP4+ supports object serialization: http://www.php.net/manual/en/function.serialize.php

Hello,

I don't get what is with the profile thing in an OO world.

Why not provide a proxy class over the client class to intercept all the get set calls and serialize as necessary?

abstract class Predis\ProxyClient extends Predis\Client
    abstract method decode(string)
    abstract method encode(mixed)

    method get(string key)
        return $this->decode(parent::get(key))

If you separated your connection class this would work allowing difference client types for one connection.

I think the annoyance for me the the proposed solution here is that it is very granular where as the php redis extension lets us set the serializer globally (only problematic for strings as it adds a few bytes).

What you have looks like dependency injection but from the example I don't see it as being as convenient in this case as it could be.

Thanks.

@joeyhub you can indeed extend Predis\Client and implement both get() and set() methods to make them serialize / deserialize stuff, but that solution wouldn't work with pipelines, transactions and clustering due to how Predis is internally structured as these features work directly against the underlying connection.

what about optional (like prefixing) variant to autoserialize (jsonify) all values, stored in redis?

$options = ['serialize' => 'json']
Was this page helpful?
0 / 5 - 0 ratings

Related issues

theDisco picture theDisco  ·  5Comments

muayyad-alsadi picture muayyad-alsadi  ·  11Comments

tillkruss picture tillkruss  ·  7Comments

Berdir picture Berdir  ·  18Comments

tillkruss picture tillkruss  ·  13Comments