Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4c72cbc

Browse files
Support closures for SUBSCRIBE/PSUBSCRIBE
Change how we detect a callback such that we can use closures in SUBSCRIBE/PSUBSCRIBE commands.
1 parent d1b1216 commit 4c72cbc

File tree

1 file changed

+33
-57
lines changed

1 file changed

+33
-57
lines changed

redis.c

Lines changed: 33 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
#define R_SUB_CALLBACK_CLASS_TYPE 1
4444
#define R_SUB_CALLBACK_FT_TYPE 2
45+
#define R_SUB_CLOSURE_TYPE 3
4546

4647
int le_redis_sock;
4748
extern int le_redis_array;
@@ -5278,21 +5279,23 @@ PHP_METHOD(Redis, publish)
52785279

52795280
PHPAPI void generic_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, char *sub_cmd)
52805281
{
5281-
zval *z_callback,*object, *array, **data;
5282+
zval *object, *array, **data;
52825283
HashTable *arr_hash;
52835284
HashPosition pointer;
52845285
RedisSock *redis_sock;
5285-
char *cmd = "", *old_cmd = NULL, *callback_ft_name;
5286-
int cmd_len, array_count, callback_ft_name_len;
5286+
char *cmd = "", *old_cmd = NULL;
5287+
int cmd_len, array_count;
52875288
zval *z_tab, **tmp;
52885289
char *type_response;
52895290

5290-
int callback_type = 0;
5291-
zval *z_o, *z_fun = NULL,*z_ret, *z_args[4];
5292-
char *method_name;
5291+
// Function call information
5292+
zend_fcall_info z_callback;
5293+
zend_fcall_info_cache z_callback_cache;
5294+
5295+
zval *z_ret, **z_args[4];
52935296

5294-
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oaz|z",
5295-
&object, redis_ce, &array, &z_callback) == FAILURE) {
5297+
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oaf",
5298+
&object, redis_ce, &array, &z_callback, &z_callback_cache) == FAILURE) {
52965299
RETURN_FALSE;
52975300
}
52985301

@@ -5352,32 +5355,10 @@ PHPAPI void generic_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, char *sub_cmd)
53525355
}
53535356
efree(z_tab);
53545357

5355-
/* verify the callback */
5356-
if(Z_TYPE_P(z_callback) == IS_ARRAY) {
5357-
5358-
/* object */
5359-
if (zend_hash_index_find(Z_ARRVAL_P(z_callback), 0, (void**)&tmp) == FAILURE) {
5360-
RETURN_FALSE;
5361-
}
5362-
z_o = *tmp;
5363-
5364-
/* method name */
5365-
if (zend_hash_index_find(Z_ARRVAL_P(z_callback), 1, (void**)&tmp) == FAILURE) {
5366-
RETURN_FALSE;
5367-
}
5368-
method_name = Z_STRVAL_PP(tmp);
5369-
5370-
ALLOC_INIT_ZVAL(z_fun);
5371-
ZVAL_STRING(z_fun, method_name, 1);
5372-
callback_type = R_SUB_CALLBACK_CLASS_TYPE;
5373-
5374-
} else if(Z_TYPE_P(z_callback) == IS_STRING) {
5375-
callback_ft_name = Z_STRVAL_P(z_callback);
5376-
callback_ft_name_len = strlen(callback_ft_name);
5377-
callback_type = R_SUB_CALLBACK_FT_TYPE;
5378-
MAKE_STD_ZVAL(z_fun);
5379-
ZVAL_STRINGL(z_fun, callback_ft_name, callback_ft_name_len, 0);
5380-
}
5358+
// Set a pointer to our return value and to our arguments.
5359+
z_callback.retval_ptr_ptr = &z_ret;
5360+
z_callback.params = z_args;
5361+
z_callback.no_separation = 0;
53815362

53825363
/* Multibulk Response, format : {message type, originating channel, message payload} */
53835364
while(1) {
@@ -5420,48 +5401,43 @@ PHPAPI void generic_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, char *sub_cmd)
54205401
}
54215402

54225403
// Always pass the Redis object through
5423-
z_args[0] = getThis();
5404+
z_args[0] = &getThis();
54245405

54255406
// Set up our callback args depending on the message type
54265407
if(is_pmsg) {
5427-
z_args[1] = *pattern;
5428-
z_args[2] = *channel;
5429-
z_args[3] = *data;
5408+
z_args[1] = pattern;
5409+
z_args[2] = channel;
5410+
z_args[3] = data;
54305411
} else {
5431-
z_args[1] = *channel;
5432-
z_args[2] = *data;
5412+
z_args[1] = channel;
5413+
z_args[2] = data;
54335414
}
5434-
5435-
switch(callback_type) {
5436-
case R_SUB_CALLBACK_CLASS_TYPE:
5437-
MAKE_STD_ZVAL(z_ret);
5438-
call_user_function(&redis_ce->function_table, &z_o, z_fun, z_ret, tab_idx, z_args TSRMLS_CC);
5439-
efree(z_ret);
5440-
break;
54415415

5442-
case R_SUB_CALLBACK_FT_TYPE:
5443-
MAKE_STD_ZVAL(z_ret);
5444-
call_user_function(EG(function_table), NULL, z_fun, z_ret, tab_idx, z_args TSRMLS_CC);
5445-
efree(z_ret);
5446-
break;
5416+
// Set our argument information
5417+
z_callback.param_count = tab_idx;
5418+
5419+
// Break if we can't call the function
5420+
if(zend_call_function(&z_callback, &z_callback_cache TSRMLS_CC) != SUCCESS) {
5421+
break;
54475422
}
5423+
5424+
// If we have a return value, free it. Note, we could use the return value to break the subscribe loop
5425+
if(z_ret) zval_ptr_dtor(&z_ret);
5426+
54485427
/* TODO: provide a way to break out of the loop. */
54495428
zval_dtor(z_tab);
54505429
efree(z_tab);
54515430
}
5452-
5453-
// Free our function
5454-
efree(z_fun);
54555431
}
54565432

5457-
/* {{{ proto void Redis::psubscribe(Array(channel1, channel2, ... channelN))
5433+
/* {{{ proto void Redis::psubscribe(Array(pattern1, pattern2, ... patternN))
54585434
*/
54595435
PHP_METHOD(Redis, psubscribe)
54605436
{
54615437
generic_subscribe_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "psubscribe");
54625438
}
54635439

5464-
/* {{{ proto void Redis::psubscribe(Array(channel1, channel2, ... channelN))
5440+
/* {{{ proto void Redis::subscribe(Array(channel1, channel2, ... channelN))
54655441
*/
54665442
PHP_METHOD(Redis, subscribe) {
54675443
generic_subscribe_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "subscribe");

0 commit comments

Comments
 (0)