diff --git a/redis.c b/redis.c index 230859dbc4..835ea2c01d 100644 --- a/redis.c +++ b/redis.c @@ -604,6 +604,51 @@ free_redis_object(zend_object *object) } } +static zend_object * +clone_redis_object(zval *this_ptr) +{ + zend_object *old_object = Z_OBJ_P(this_ptr); + redis_object *old_redis = PHPREDIS_GET_OBJECT(redis_object, old_object); + redis_object *redis = ecalloc(1, sizeof(redis_object) + zend_object_properties_size(old_object->ce)); + + if (old_redis->sock) { + redis->sock = redis_sock_create(ZSTR_VAL(old_redis->sock->host), ZSTR_LEN(old_redis->sock->host), + old_redis->sock->port, + old_redis->sock->timeout, + old_redis->sock->read_timeout, + old_redis->sock->persistent, + ZSTR_VAL(old_redis->sock->persistent_id), + old_redis->sock->retry_interval); + + if (old_redis->sock->stream_ctx) { + redis_sock_set_stream_context(redis->sock, &old_redis->sock->stream_ctx->options); + } + + if (old_redis->sock->user) { + redis_sock_set_auth(redis->sock, old_redis->sock->user, old_redis->sock->pass); + } + + if (redis_sock_server_open(redis->sock) < 0) { + if (redis->sock->err) { + REDIS_THROW_EXCEPTION(ZSTR_VAL(redis->sock->err), 0); + } + redis_free_socket(redis->sock); + redis->sock = NULL; + } + } + + zend_object_std_init(&redis->std, old_object->ce); + object_properties_init(&redis->std, old_object->ce); + + memcpy(&redis_object_handlers, zend_get_std_object_handlers(), sizeof(redis_object_handlers)); + redis_object_handlers.offset = XtOffsetOf(redis_object, std); + redis_object_handlers.free_obj = free_redis_object; + redis_object_handlers.clone_obj = clone_redis_object; + redis->std.handlers = &redis_object_handlers; + + return &redis->std; +} + zend_object * create_redis_object(zend_class_entry *ce) { @@ -617,6 +662,7 @@ create_redis_object(zend_class_entry *ce) memcpy(&redis_object_handlers, zend_get_std_object_handlers(), sizeof(redis_object_handlers)); redis_object_handlers.offset = XtOffsetOf(redis_object, std); redis_object_handlers.free_obj = free_redis_object; + redis_object_handlers.clone_obj = clone_redis_object; redis->std.handlers = &redis_object_handlers; return &redis->std; diff --git a/redis_array.c b/redis_array.c index 9d6883c305..2cf10ee0bf 100644 --- a/redis_array.c +++ b/redis_array.c @@ -196,6 +196,7 @@ create_redis_array_object(zend_class_entry *ce) memcpy(&redis_array_object_handlers, zend_get_std_object_handlers(), sizeof(redis_array_object_handlers)); redis_array_object_handlers.offset = XtOffsetOf(redis_array_object, std); redis_array_object_handlers.free_obj = free_redis_array_object; + redis_array_object_handlers.clone_obj = NULL; obj->std.handlers = &redis_array_object_handlers; return &obj->std; diff --git a/redis_cluster.c b/redis_cluster.c index 402c23b7cc..90e8dd9b2d 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -333,6 +333,7 @@ zend_object * create_cluster_context(zend_class_entry *class_type) { memcpy(&RedisCluster_handlers, zend_get_std_object_handlers(), sizeof(RedisCluster_handlers)); RedisCluster_handlers.offset = XtOffsetOf(redisCluster, std); RedisCluster_handlers.free_obj = free_cluster_context; + RedisCluster_handlers.clone_obj = NULL; cluster->std.handlers = &RedisCluster_handlers; diff --git a/sentinel_library.c b/sentinel_library.c index 0fe64cc145..475ebb72a9 100644 --- a/sentinel_library.c +++ b/sentinel_library.c @@ -25,6 +25,7 @@ create_sentinel_object(zend_class_entry *ce) memcpy(&redis_sentinel_object_handlers, zend_get_std_object_handlers(), sizeof(redis_sentinel_object_handlers)); redis_sentinel_object_handlers.offset = XtOffsetOf(redis_sentinel_object, std); redis_sentinel_object_handlers.free_obj = free_redis_sentinel_object; + redis_sentinel_object_handlers.clone_obj = NULL; obj->std.handlers = &redis_sentinel_object_handlers; return &obj->std; diff --git a/tests/RedisTest.php b/tests/RedisTest.php index ed8b53f253..616306440b 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -138,6 +138,22 @@ public function testMinimumVersion() $this->assertTrue(version_compare($this->version, "2.4.0") >= 0); } + public function testClone() + { + if (get_class($this->redis) !== 'Redis') { + $this->markTestSkipped(); + return; + } + + $new = clone $this->redis; + /* check that connection works */ + $this->assertTrue($new->ping()); + /* confirm socket settings are disconnected from source object */ + $this->assertTrue($new->setOption(Redis::OPT_PREFIX, 'test')); + $this->assertEquals($new->getOption(Redis::OPT_PREFIX), 'test'); + $this->assertFalse($this->redis->getOption(Redis::OPT_PREFIX)); + } + public function testPing() { /* Reply literal off */ $this->assertTrue($this->redis->ping());