php-redis - есть ли способ сохранить объект PHP в Redis без его сериализации?

Я пытаюсь сохранить URL-адрес запроса пользователя в качестве ключа и объект PHP, соответствующий этому ключу, в качестве значения в Redis. Я пробовал следующее:

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

Однако в этом коде значение ключа URL, которое хранится в Redis, имеет тип string со значением, равным «Object», а не фактическому объекту PHP. Есть ли способ сохранить объект PHP без его сериализации?


person Sai Wai Maung    schedule 03.11.2014    source источник
comment
Есть ли причина, по которой вы не можете сериализовать его? Это был бы самый простой способ.   -  person bcmcfc    schedule 03.11.2014
comment
Простой ответ: нет ... Redis не зависит от языка, он не знает, что такое объект PHP, поэтому логически нельзя ожидать, что он сможет спасти такое существо ... вам нужно преобразовать объект в какой-то формат, который Redis может сохранить, например, текстовое представление   -  person Mark Baker    schedule 03.11.2014


Ответы (4)


Как видно из типов данных Redis, Redis поддерживает только эти 5 типов данных:

  • Нить
  • Список
  • Установленный
  • Хеш
  • Сортированный набор

Итак, не существует типа данных объекта, и поэтому вы не можете сохранить объект непосредственно в качестве значения. Вы должны сначала сериализовать его (или, например, закодировать JSON с помощью функции json_encode).

Есть ли проблема с сериализацией, когда вы настаиваете на непосредственном хранении своих объектов?

Обновление: Согласно тому, что вы сказали в комментариях, вы можете использовать подход, указанный в этом ответе

Итак, вы можете использовать:

$xml = $simpleXmlElem->asXML();

перед сериализацией, а затем после unserialize() используйте следующий код:

$simpleXmlElem = simplexml_load_string($xml);

Таким образом, вам не нужно напрямую сериализовать встроенный объект PHP, такой как SimpleXmlElement, и проблем не возникнет.

person Aliweb    schedule 03.11.2014
comment
Какой из пяти типов данных, поддерживаемых Redis, является наиболее оптимальным, в который мне следует сериализовать свой объект PHP? - person Sai Wai Maung; 03.11.2014
comment
Наиболее логичным типом является String для его хранения, а функция serialize - лучший выбор, а также, как сказано в руководстве по PHP, цель этой функции - сделать значение сохраняемым: php.net/manual/en/function.serialize.php - person Aliweb; 03.11.2014
comment
когда я использовал сериализацию ($ this- ›page); Я получил эту ошибку: Исключение: сериализация SimpleXMLElement не разрешена - person Sai Wai Maung; 03.11.2014
comment
Ну, встроенные объекты PHP не могут быть сериализованы. Все ли объекты, которые вы хотите сохранить в Redis, относятся к этому типу или существуют объекты других типов? Вы также можете рассмотреть json_encode как еще один вариант. - person Aliweb; 03.11.2014
comment
Я храню в Redis только такие объекты. Я тоже пробую json_encode($this->page), но он хранит пустые {} в Redis. - person Sai Wai Maung; 03.11.2014
comment
Я сделал, и это не сработало. Проблема в том, как мы создаем объект PHP, вместо этого я изменил это. Спасибо! - person Sai Wai Maung; 06.11.2014

Сериализация была бы самым простым способом.

Альтернативой является json_encode только параметры, необходимые для последующего восстановления объекта. Один из способов сделать это - использовать интерфейс JsonSerialize в PHP 5.4. Вы хотели бы извлечь различные свойства с помощью jsonSerialize, а затем предоставить средства для их передачи обратно в свой класс, когда вы извлекаете элемент из 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,
        ];
    }

}

Таким образом, вы легко сможете выполнить реконструкцию из JSON. Вы можете добавить для этого вспомогательный метод или просто вызвать сеттеры.

person bcmcfc    schedule 03.11.2014
comment
когда я использовал json_encode ($ this- ›page), он сохраняется в Redis как '{}'. Не могли бы вы привести пример кода на основе вашего ответа? - person Sai Wai Maung; 03.11.2014
comment
Будет, потому что вы еще не изменили класс, экземпляром которого является ваш $this->page. Возможно, у вас не получится, если это часть фреймворка. - person bcmcfc; 03.11.2014

Вот как я это делаю:

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);
    }
}

Использование:

$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;

Выход:

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:{}
person Sinan Eldem    schedule 15.11.2016

Дополнение к ответу Aliweb!

Redis поддерживает целые числа, а также такие действия, как INCR, INCRBY, DECR и DECRBY.

По поводу вопроса:

Выполняйте сериализацию только в том случае, если это не String или Int. Сериализация - дорогостоящая операция!

в GET и HGET попробуйте посмотреть, что, если он сериализован:

'

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

'

person Dimitris Samaras    schedule 05.05.2017