PHP参数解析源码

PHP 使用 ZEND_PARSE_PARAMETERS_START ...  ZEND_PARSE_PARAMETERS_END 进行参数解析

PHP_FUNCTION(strpos)
{
	zval *needle;
	zend_string *haystack;
	const char *found = NULL;
	char  needle_char[2];
	zend_long  offset = 0;
    // 解析参数
	ZEND_PARSE_PARAMETERS_START(2, 3)
		Z_PARAM_STR(haystack)
		Z_PARAM_ZVAL(needle)
		Z_PARAM_OPTIONAL
		Z_PARAM_LONG(offset)
	ZEND_PARSE_PARAMETERS_END();
    ...
    ...
    ...
}
ZEND_PARSE_PARAMETERS_START ZEND_PARSE_PARAMETERS_END 为宏定义(以下代码位于Zend/zend_API.h)       
#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
		const int _flags = (flags); \
		int _min_num_args = (min_num_args); \
		int _max_num_args = (max_num_args); \
		int _num_args = EX_NUM_ARGS(); \
		int _i = 0; \
		zval *_real_arg, *_arg = NULL; \
		zend_expected_type _expected_type = Z_EXPECTED_LONG; \
		char *_error = NULL; \
		zend_bool _dummy; \
		zend_bool _optional = 0; \
		int _error_code = ZPP_ERROR_OK; \
		((void)_i); \
		((void)_real_arg); \
		((void)_arg); \
		((void)_expected_type); \
		((void)_error); \
		((void)_dummy); \
		((void)_optional); \
		\
		do { \
			if (UNEXPECTED(_num_args < _min_num_args) || \
			    (UNEXPECTED(_num_args > _max_num_args) && \
			     EXPECTED(_max_num_args >= 0))) { \
				if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_parameters_count_exception(_min_num_args, _max_num_args); \
					} else { \
						zend_wrong_parameters_count_error(_min_num_args, _max_num_args); \
					} \
				} \
				_error_code = ZPP_ERROR_FAILURE; \
				break; \
			} \
			_real_arg = ZEND_CALL_ARG(execute_data, 0);

#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args) \
	ZEND_PARSE_PARAMETERS_START_EX(0, min_num_args, max_num_args)

#define ZEND_PARSE_PARAMETERS_END_EX(failure) \
		} while (0); \
		if (UNEXPECTED(_error_code != ZPP_ERROR_OK)) { \
			if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { \
				if (_error_code == ZPP_ERROR_WRONG_CALLBACK) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_callback_exception(_i, _error); \
					} else { \
						zend_wrong_callback_error(_i, _error); \
					} \
				} else if (_error_code == ZPP_ERROR_WRONG_CLASS) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_parameter_class_exception(_i, _error, _arg); \
					} else { \
						zend_wrong_parameter_class_error(_i, _error, _arg); \
					} \
				} else if (_error_code == ZPP_ERROR_WRONG_ARG) { \
					if (_flags & ZEND_PARSE_PARAMS_THROW) { \
						zend_wrong_parameter_type_exception(_i, _expected_type, _arg); \
					} else { \
						zend_wrong_parameter_type_error(_i, _expected_type, _arg); \
					} \
				} \
			} \
			failure; \
		} \
	} while (0)

#define ZEND_PARSE_PARAMETERS_END() \
	ZEND_PARSE_PARAMETERS_END_EX(return)

替换后参数解析代码如下(以strpos中参数解析为例)

do { 
        const int _flag = (0);  // 0 为ZEND_PARSE_PARAMETERS_START_EX(0, min_num_args, max_num_args) 中第一个参数
        int _min_num_args = (2); // 2 为 ZEND_PARSE_PARAMETERS_START(2, 3)中2
        int _max_num_args = (3); // 3 为 ZEND_PARSE_PARAMETERS_START(2, 3)中3
        int _num_args =(execute_data)->This.u2.num_args; // 参见 struct _zval_struct  参数数量
        int _i = 0; 
        zval *_real_arg, *_arg = NULL; 
        zend_expected_type _expected_type = Z_EXPECTED_LONG; 
        char *_error = NULL; 
        zend_bool _dummy; 
        zend_bool _optional = 0; 
        int _error_code = ZPP_ERROR_OK; 
        ((void)_i); 
        ((void)_real_arg); 
        ((void)_arg); 
        ((void)_expected_type); 
        ((void)_error); 
        ((void)_dummy); 
        ((void)_optional); 
        // 校验参数数量
        do { 
            if (UNEXPECTED(_num_args < _min_num_args) || 
                (UNEXPECTED(_num_args > _max_num_args) && 
                 EXPECTED(_max_num_args >= 0))) { 
                if (!(_0 & ZEND_PARSE_PARAMS_QUIET)) { 
                    if (_0 & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_parameters_count_exception(_min_num_args, _max_num_args); 
                    } else { 
                        zend_wrong_parameters_count_error(_min_num_args, _max_num_args); 
                    } 
                } 
                _error_code = ZPP_ERROR_FAILURE; 
                break; 
            } 
            _real_arg = ZEND_CALL_ARG(execute_data, 0);
            Z_PARAM_STR(haystack) // 解析参数
            Z_PARAM_ZVAL(needle) // 解析参数
            _optional = 1;
            Z_PARAM_LONG(offset) // 解析参数
        } while (0); 
        if (UNEXPECTED(_error_code != ZPP_ERROR_OK)) { 
            if (!(_flags & ZEND_PARSE_PARAMS_QUIET)) { 
                if (_error_code == ZPP_ERROR_WRONG_CALLBACK) { 
                    if (_flags & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_callback_exception(_i, _error); 
                    } else { 
                        zend_wrong_callback_error(_i, _error); 
                    } 
                } else if (_error_code == ZPP_ERROR_WRONG_CLASS) { 
                    if (_flags & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_parameter_class_exception(_i, _error, _arg); 
                    } else { 
                        zend_wrong_parameter_class_error(_i, _error, _arg); 
                    } 
                } else if (_error_code == ZPP_ERROR_WRONG_ARG) { 
                    if (_flags & ZEND_PARSE_PARAMS_THROW) { 
                        zend_wrong_parameter_type_exception(_i, _expected_type, _arg); 
                    } else { 
                        zend_wrong_parameter_type_error(_i, _expected_type, _arg); 
                    } 
                } 
            } 
            return; 
        } 
    } while (0)
Z_PARAM_STR(haystack) Z_PARAM_ZVAL(needle) Z_PARAM_LONG(offset) 将用户传入参数值解析至指定参数
#define Z_PARAM_STR_EX2(dest, check_null, deref, separate) \
		Z_PARAM_PROLOGUE(deref, separate); \
		if (UNEXPECTED(!zend_parse_arg_str(_arg, &dest, check_null))) { \
			_expected_type = Z_EXPECTED_STRING; \
			_error_code = ZPP_ERROR_WRONG_ARG; \
			break; \
		}

#define Z_PARAM_STR_EX(dest, check_null, separate) \
	Z_PARAM_STR_EX2(dest, check_null, separate, separate)

#define Z_PARAM_STR(dest) \
	Z_PARAM_STR_EX(dest, 0, 0)
#define Z_PARAM_ZVAL_EX2(dest, check_null, deref, separate) \
		Z_PARAM_PROLOGUE(deref, separate); \
		zend_parse_arg_zval_deref(_arg, &dest, check_null);

#define Z_PARAM_ZVAL_EX(dest, check_null, separate) \
	Z_PARAM_ZVAL_EX2(dest, check_null, separate, separate)

#define Z_PARAM_ZVAL(dest) \
	Z_PARAM_ZVAL_EX(dest, 0, 0)
#define Z_PARAM_LONG_EX2(dest, is_null, check_null, deref, separate) \
		Z_PARAM_PROLOGUE(deref, separate); \
		if (UNEXPECTED(!zend_parse_arg_long(_arg, &dest, &is_null, check_null, 0))) { \
			_expected_type = Z_EXPECTED_LONG; \
			_error_code = ZPP_ERROR_WRONG_ARG; \
			break; \
		}

#define Z_PARAM_LONG_EX(dest, is_null, check_null, separate) \
	Z_PARAM_LONG_EX2(dest, is_null, check_null, separate, separate)

#define Z_PARAM_LONG(dest) \
	Z_PARAM_LONG_EX(dest, _dummy, 0, 0)

先调用 Z_PARAM_PROLOGUE(deref, separate) 进行参数校验。_i表示第几个参数;_arg为第_i个参数。

#define Z_PARAM_PROLOGUE(deref, separate) \
	++_i; \
	ZEND_ASSERT(_i <= _min_num_args || _optional==1); \
	ZEND_ASSERT(_i >  _min_num_args || _optional==0); \
	if (_optional) { \
		if (UNEXPECTED(_i >_num_args)) break; \
	} \
	_real_arg++; \
	_arg = _real_arg; \
	if (deref) { \
		if (EXPECTED(Z_ISREF_P(_arg))) { \
			_arg = Z_REFVAL_P(_arg); \
		} \
	} \
	if (separate) { \
		SEPARATE_ZVAL_NOREF(_arg); \
	}

然后分别调用 zend_parse_arg_str  zend_parse_arg_zval_deref zend_parse_arg_long 将

_arg赋值dest完成参数解析

上一篇:Java中的类和类加载机制


下一篇:阿里二面:main 方法可以继承吗?