PHP源码学习之 —— strtr()函数

对应源码在PHP7的地址为:/ext/standard/string.c

定位某个函数的源码可以用grep匹配PHP_FUNCTION(strtr),或者把源码下载下来在PHPstrom中查找

源码:

PHP_FUNCTION(strtr)
{
	zval *from;
	zend_string *str;
	char *to = NULL;
	size_t to_len = 0;
	int ac = ZEND_NUM_ARGS();

	ZEND_PARSE_PARAMETERS_START(2, 3)
		Z_PARAM_STR(str)
		Z_PARAM_ZVAL(from)
		Z_PARAM_OPTIONAL
		Z_PARAM_STRING(to, to_len)
	ZEND_PARSE_PARAMETERS_END();

	if (ac == 2 && Z_TYPE_P(from) != IS_ARRAY) {
		php_error_docref(NULL, E_WARNING, "The second argument is not an array");
		RETURN_FALSE;
	}

	/* shortcut for empty string */
	if (ZSTR_LEN(str) == 0) {
		RETURN_EMPTY_STRING();
	}

	if (ac == 2) {
		HashTable *pats = Z_ARRVAL_P(from);

		if (zend_hash_num_elements(pats) < 1) {
			RETURN_STR_COPY(str);
		} else if (zend_hash_num_elements(pats) == 1) {
			zend_long num_key;
			zend_string *str_key, *tmp_str, *replace, *tmp_replace;
			zval *entry;

			ZEND_HASH_FOREACH_KEY_VAL(pats, num_key, str_key, entry) {
				tmp_str = NULL;
				if (UNEXPECTED(!str_key)) {
					str_key = tmp_str = zend_long_to_str(num_key);
				}
				replace = zval_get_tmp_string(entry, &tmp_replace);
				if (ZSTR_LEN(str_key) < 1) {
					RETVAL_STR_COPY(str);
				} else if (ZSTR_LEN(str_key) == 1) {
					RETVAL_STR(php_char_to_str_ex(str,
								ZSTR_VAL(str_key)[0],
								ZSTR_VAL(replace),
								ZSTR_LEN(replace),
								1,
								NULL));
				} else {
					zend_long dummy;
					RETVAL_STR(php_str_to_str_ex(str,
								ZSTR_VAL(str_key), ZSTR_LEN(str_key),
								ZSTR_VAL(replace), ZSTR_LEN(replace), &dummy));
				}
				zend_tmp_string_release(tmp_str);
				zend_tmp_string_release(tmp_replace);
				return;
			} ZEND_HASH_FOREACH_END();
		} else {
			php_strtr_array(return_value, str, pats);
		}
	} else {
		convert_to_string_ex(from);

		RETURN_STR(php_strtr_ex(str,
				  Z_STRVAL_P(from),
				  to,
				  MIN(Z_STRLEN_P(from), to_len)));
	}
}

最开始定义了五个变量用于保存参数相关信息,变量类型请自行百度PHP7中的zval

其中str、from、to分别对应strtr函数里的三个参数

to_len保存转换之后字符串的长度,默认为0

ac保存参数个数,用ZEND_NUM_ARGS()函数获取

zval *from;
zend_string *str;
char *to = NULL;
size_t to_len = 0;
int ac = ZEND_NUM_ARGS();

下边是用 ZEND_PARSE_PARAMETERS相应函数接收传过来的参数,分别用START和END标记开始和结束,不同的参数类型对应着不同的接收方法

ZEND_PARSE_PARAMETERS_START(2, 3)
		Z_PARAM_STR(str)
		Z_PARAM_ZVAL(from)
		Z_PARAM_OPTIONAL
		Z_PARAM_STRING(to, to_len)
ZEND_PARSE_PARAMETERS_END();

接下来是验证传入参数个数,如果个数是2,并且第二个参数from不是数组(具体原因百度php函数strtr),否则报错

if (ac == 2 && Z_TYPE_P(from) != IS_ARRAY) {
		php_error_docref(NULL, E_WARNING, "The second argument is not an array");
		RETURN_FALSE;
}

自己写个程序验证一下:
PHP:
<?php echo strtr('hello, world', 'hello'); ?>

报错:Warning</b>:  strtr(): The second argument is not an array in /home/XXX/test.php on line 2

下边当要处理的字符串为空时,返回结果为空字符串

/* shortcut for empty string */
	if (ZSTR_LEN(str) == 0) {
		RETURN_EMPTY_STRING();
}

同样自己写程序验证:

php:<?php var_dump( strtr('', 'hello', 'word') ); ?>

输出结果:string(0) ""

下边这一大段的处理,是当参数为2的时候,去替换所有的字符串,由于C的基础不是太好,暂时没有去深究实现

最后则是返回处理结果

PS:由于工作比较忙,并且暂时还未涉及到PHP扩展开发,所以只是在有时间的时候看一下源码,随看随更

猜你喜欢

转载自blog.csdn.net/why444216978/article/details/86554143