看swoole_client的demo,其支持回调函数,也就是PHP业务侧设置了相应的回调函数,在达到回调函数的条件时,会触发相应的回调,目前swoole_client支持的回调函数有connect,receive等,swoole_client里设置回调函数是通过on函数实现,这篇文章我们分析下其回调函数的实现。
static PHP_METHOD(swoole_client, on)
{
char *cb_name;
zend_size_t cb_name_len;
zval *zcallback;
//解析输入参数信息,解析的参数有回调函数名,函数名长度,函数实现等。
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &cb_name, &cb_name_len, &zcallback) == FAILURE)
{
return;
}
//读取swoole_client的type属性信息
zval *ztype = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), SW_STRL("type")-1, 0 TSRMLS_CC);
if (ztype == NULL || ZVAL_IS_NULL(ztype))
{
swoole_php_fatal_error(E_ERROR, "get swoole_client->type failed.");
return;
}
if (!(Z_LVAL_P(ztype) & SW_FLAG_ASYNC))//判断是否是异步模式,异步模式不允许设置回调函数
{
swoole_php_fatal_error(E_ERROR, "can't register event callback functions in SYNC mode.");
return;
}
//读取swoole_client的回调函数信息
client_callback *cb = (client_callback *) swoole_get_property(getThis(), client_property_callback);
if (!cb)//如果为空
{
cb = (client_callback *) emalloc(sizeof(client_callback));//申请回调函数结构空间
bzero(cb, sizeof(client_callback));//空间初始化
swoole_set_property(getThis(), client_property_callback, cb);//设置swoole_client的属性信息
}
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
char *func_name = NULL;
zend_fcall_info_cache func_cache;
if (!sw_zend_is_callable_ex(zcallback, NULL, 0, &func_name, NULL, &func_cache, NULL TSRMLS_CC))//检查输入信息是否是可以执行的,这里通过php底层方法直接判断
{
swoole_php_fatal_error(E_ERROR, "Function '%s' is not callable", func_name);
efree(func_name);
return;
}
efree(func_name);
#elif defined(PHP_SWOOLE_CHECK_CALLBACK)
char *func_name = NULL;
if (!sw_zend_is_callable(zcallback, 0, &func_name TSRMLS_CC))
{
swoole_php_fatal_error(E_ERROR, "Function '%s' is not callable", func_name);
efree(func_name);
return;
}
efree(func_name);
#endif
if (strncasecmp("connect", cb_name, cb_name_len) == 0)//绑定connect回调函数,绑定到swoole_client对应的内部对象时,就变成了onConnect函数。
{
zend_update_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onConnect"), zcallback TSRMLS_CC);
cb->onConnect = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onConnect"), 0 TSRMLS_CC);
sw_copy_to_stack(cb->onConnect, cb->_onConnect);
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
cb->cache_onConnect = func_cache;
#endif
}
else if (strncasecmp("receive", cb_name, cb_name_len) == 0)//绑定receive回调函数,绑定到swoole_client对应的内部对象时,就变成了onReceive函数。
{
zend_update_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onReceive"), zcallback TSRMLS_CC);
cb->onReceive = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onReceive"), 0 TSRMLS_CC);
sw_copy_to_stack(cb->onReceive, cb->_onReceive);
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
cb->cache_onReceive = func_cache;
#endif
}
else if (strncasecmp("close", cb_name, cb_name_len) == 0)//绑定close回调函数,绑定到swoole_client对应的内部对象时,就变成了onClose函数。
{
zend_update_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onClose"), zcallback TSRMLS_CC);
cb->onClose = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onClose"), 0 TSRMLS_CC);
sw_copy_to_stack(cb->onClose, cb->_onClose);
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
cb->cache_onClose = func_cache;
#endif
}
else if (strncasecmp("error", cb_name, cb_name_len) == 0)//绑定error回调函数,绑定到swoole_client对应的内部对象时,就变成了onError函数。
{
zend_update_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onError"), zcallback TSRMLS_CC);
cb->onError = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onError"), 0 TSRMLS_CC);
sw_copy_to_stack(cb->onError, cb->_onError);
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
cb->cache_onError = func_cache;
#endif
}
else if (strncasecmp("bufferFull", cb_name, cb_name_len) == 0)//绑定bufferFull回调函数,绑定到swoole_client对应的内部对象时,就变成了onBufferFull函数。
{
zend_update_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onBufferFull"), zcallback TSRMLS_CC);
cb->onBufferFull = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onBufferFull"), 0 TSRMLS_CC);
sw_copy_to_stack(cb->onBufferFull, cb->_onBufferFull);
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
cb->cache_onBufferFull = func_cache;
#endif
}
else if (strncasecmp("bufferEmpty", cb_name, cb_name_len) == 0)//绑定bufferEmpty回调函数,绑定到swoole_client对应的内部对象时,就变成了onBufferEmpty函数。
{
zend_update_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onBufferEmpty"), zcallback TSRMLS_CC);
cb->onBufferEmpty = sw_zend_read_property(swoole_client_class_entry_ptr, getThis(), ZEND_STRL("onBufferEmpty"), 0 TSRMLS_CC);
sw_copy_to_stack(cb->onBufferEmpty, cb->_onBufferEmpty);
#ifdef PHP_SWOOLE_ENABLE_FASTCALL
cb->cache_onBufferEmpty = func_cache;
#endif
}
else
{
swoole_php_fatal_error(E_WARNING, "Unknown event callback type name '%s'.", cb_name);
RETURN_FALSE;
}
RETURN_TRUE;
}
上面我们分析了绑定的逻辑,我们下面看其中回调函数的执行逻辑。
static sw_inline void execute_onConnect(swClient *cli)
{
if (cli->timer)
{
swTimer_del(&SwooleG.timer, cli->timer);
cli->timer = NULL;
}
cli->onConnect(cli);//调用onConnect回调函数,这时候会把自己当参数带过去
}