php-redis - Is there a way to store PHP object in Redis without serializing it?
Asked Answered
P

4

13

I am trying to store user' request URL as the key and a PHP object corresponding to that key as the value in Redis. I tried the following:

$redisClient = new Redis();
$redisClient->connect('localhost', 6379);
$redisClient->set($_SERVER['REQUEST_URI'], $this->page);
$redisTest = $redisClient->get($_SERVER['REQUEST_URI']);
var_dump($redisTest);

However, with this code the value of the URL key that is being stored in Redis is type of string with the value equal to 'Object' instead of the actual PHP object. Is there a way to store a PHP object without serializing it?

Politburo answered 3/11, 2014 at 16:12 Comment(2)
Is there a reason you can't serialize it? That'd be the most straightforward way.Andreas
Simple answer, "No".... Redis is language-agnostic, it has no idea what a PHP Object is, so can't logically be expected to be capable of saving such a creature.... you need to convert the object to some format that redis can save, such as a text representationOestriol
I
11

As you can see in Redis data types, Redis only supports these 5 data types:

  • String
  • List
  • Set
  • Hash
  • Sorted Set

So, there is no object data-type and therefor you are not able to store an object directly as a value. You have to serialize it first (or JSON-encode it with the json_encode function for example).

Is there any problem with serializing that you insist on storing your objects directly?

Update: According to what you said in the comments, you can use the approach indicated in this answer

So you can use:

$xml = $simpleXmlElem->asXML();

before serialization, and then after unserialize(), use the following code:

$simpleXmlElem = simplexml_load_string($xml);

In this way, you don't have to serialize a PHP built-in object like SimpleXmlElement directly and there will be no problems.

Italic answered 3/11, 2014 at 16:17 Comment(6)
out of the five data types that is supported by Redis, which format is the most optimal type that I should serialize my PHP object to?Politburo
The most logical type is String in order to store it and the serialize function is the best choice and also as the PHP manual says, the purpose of this function is to make a value storable : php.net/manual/en/function.serialize.phpItalic
when I used serialize($this->page); I got this error: Exception: Serialization of 'SimpleXMLElement' is not allowedPolitburo
Well PHP built-in objects cannot be serialized. Are all the objects you want to store in Redis of this type or there are also other types of objects? You can also consider json_encode as another option.Italic
I am storing only this type of objects in Redis. I also try json_encode($this->page), but it store empty {} in Redis.Politburo
I did and it didn't work. The issue is on the way we create PHP object, I changed that instead. Thanks!Politburo
A
3

Serializing would be the most straightforward way.

An alternative is to json_encode only the parameters required to reconstruct the object later. One way to do this is using PHP 5.4's JsonSerialize interface. You'd want to extract various properties using jsonSerialize and then provide the means to pass them back into your class when you pull the item from Redis.


class MyPage implements JsonSerializable
{

    protected $p1;
    protected $p2;

    /**
     * @param mixed $p1
     */
    public function setP1($p1)
    {
        $this->p1 = $p1;
    }

    /**
     * @param mixed $p2
     */
    public function setP2($p2)
    {
        $this->p2 = $p2;
    }

    /**
     * (PHP 5 &gt;= 5.4.0)<br/>
     * Specify data which should be serialized to JSON
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
     * @return mixed data which can be serialized by <b>json_encode</b>,
     * which is a value of any type other than a resource.
     */
    public function jsonSerialize()
    {
        return [
            'p1' => $this->p1,
            'p2' => $this->p2,
        ];
    }

}

In this way you're easily able to reconstruct from JSON. You could add a helper method to do that or just call the setters.

Andreas answered 3/11, 2014 at 16:16 Comment(2)
when I used json_encode($this->page), it stores into Redis as '{}'. Could you give code example based on your answer?Politburo
It will, because you won't have changed the class that your $this->page is an instance of yet. You may not be able to if it's part of a framework.Andreas
V
2

Here is how I do it:

class Cache extends Predis\Client {
    protected $prefix = 'myapp:';

    public function take($key, $value = null, $ttl = null) {
        $value = is_object($value) ? serialize($value) : $value;
        $key   = $this->prefix . $key;
        if (!$this->exists($key)) {
            if (intval($ttl)) {
                $this->setEx($key, $ttl, $value);
            } else {
                $this->set($key, $value);
            }
        }
        return $this->get($key);
    }
}

Usage:

$cache = new Cache;

$lorem     = 'Lorem ipsum dolor sit amet';
$loremLong = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';

$cachedLorem          = $cache->take('lorem', $lorem);
$cachedLoremLong      = $cache->take('loremLong', $loremLong);
$cachedLoremTtl       = $cache->take('loremTtl', $lorem, 30);
$cachedLoremGet       = $cache->take('lorem');
$cachedLoremObject    = $cache->take('loremObject', new stdClass);
$cachedLoremObjectTtl = $cache->take('loremObjectTtl', new stdClass, 45);

echo $cachedLorem;
echo $cachedLoremLong;
echo $cachedLoremTtl;
echo $cachedLoremGet;
echo $cachedLoremObject;
echo $cachedLoremObjectTtl;

Output:

Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
O:8:"stdClass":0:{}
O:8:"stdClass":0:{}
Vannessavanni answered 15/11, 2016 at 11:4 Comment(0)
W
0

An addition to Aliweb's answer!

Redis supports integers as well as actions like INCR, INCRBY, DECR and DECRBY.

As for the question:

Serialize only if is not a String or Int. Serialization is a costly operation!

on GET and HGET try to see what if it is serialized:

'

private function string_unserialize($str){
        $data = @unserialize($str);
        if ($str === 'b:0;'){
            return 0;
        }elseif($data !== false){
            return $data;
        }else {
            return $str;
        }
    }

'

Weaponless answered 5/5, 2017 at 9:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.