str_replace — Substring replacement [str_replace]
mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
php functionstr_replace: Returns a string or array. The string or array is all search are all replaced by .
Now we can know some usage of this function, such as: str_replace("#", "-", "dizaz#7#final"), str_replace(array('#', '$'), " -", "dizaz#7$final"), etc., how are these calling methods implemented inside PHP? In view of [In-depth understanding of PHP kernel], I will do a small analysis here.
Test code: Copy code
The code is as follows:
$object = "dizaz #7#final"; $res = str_replace("#", "-", $object); echo $res;
As above, start with the characters "#" is replaced with the character "-" at the beginning.
Preparatory work:
Download the PHP source code, download it from http://www.php.net
Create your own code reading tool [I use VIM+CSCOPE] Also : Linux users also recommend the graphical source code viewing tool kscope [google]
compilation tool [gcc], debugging tool [gdb], and: GDB graphical port DDD is also very good, recommend
to compile PHP source code, Remember to use --enable-debug [Of course, you also hope to use ./configure --help to take a look at some of the compilation options provided by PHP, you will gain a lot]
Through [In-depth understanding of PHP Kernel] reading, it is not difficult to find that the directory where the standard functions provided by PHP is in the PHP-SOURCE-DIR/ext/standard directory. Since it is a string function, it is easy for us to find the file string implemented by the str_replace function in this directory. .c, the next step will be to analyze this file. [Of course it is easy to lock with CScope, use: cs find s str_replace]
/* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count])
/* {{{ php_str_replace_common
*/
static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
{
/**
* TODO
* typedef struct _zval_struct zval;
* typedef struct _zend_class_entry zend_class_entry
*
* struct _zval_struct {
* zvalue_value value;
* zend_uint refcount__gc;
* zend_uchar type;
* zend_uchar is_ref__gc;
* };
*
* typedef union _zvalue_value {
* long lval;
* double dval;
* struct {
* char *val;
* int len;
* } str;
* HashTable *ht;
* zend_object_value obj;
* } zvalue_value;
*
* typedef struct _zend_object {
* zend_class_entry *ce;
* HashTable *properties;
* HashTable *guards;
* } zend_object;
*
*/
zval **subject, **search, **replace, **subject_entry, **zcount = NULL;
zval *result;
char *string_key;
uint string_key_len;
ulong num_key;
int count = 0;
int argc = ZEND_NUM_ARGS();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &search, &replace, &subject, &zcount) == FAILURE) {
return;
}
SEPARATE_ZVAL(search);
SEPARATE_ZVAL(replace);
SEPARATE_ZVAL(subject);
/* Make sure we're dealing with strings and do the replacement. */
if (Z_TYPE_PP(search) != IS_ARRAY) {
....//代码省滤
} else { /* if subject is not an array */
php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL);
}
if (argc > 3) {
zval_dtor(*zcount);
ZVAL_LONG(*zcount, count);
}
}
/* }}} */
继续跟踪php_str_replace_in_subject
复制代码 代码如下:
/* {{{ php_str_replace_in_subject
*/
static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count)
{
zval **search_entry,
**replace_entry = NULL,
temp_result;
char *replace_value = NULL;
int replace_len = 0;
/* Make sure we're dealing with strings. */
convert_to_string_ex(subject);
Z_TYPE_P(result) = IS_STRING;
if (Z_STRLEN_PP(subject) == 0) {
ZVAL_STRINGL(result, "", 0, 1);
return;
}
/* If search is an array */
if (Z_TYPE_P(search) == IS_ARRAY) {
...//不走这步
} else {
if (Z_STRLEN_P(search) == 1) { //例子中只有”#“所以,执行这一步。
php_char_to_str_ex(Z_STRVAL_PP(subject),//subject的值,也就是dizaz#7#final
Z_STRLEN_PP(subject), //获取subject的长度
Z_STRVAL_P(search)[0], //由于只有1个”#”,所以只需要第一个字符
Z_STRVAL_P(replace), //所要替换成的字符,现在是“-”
Z_STRLEN_P(replace), //目标字符的长度,现在为1
result, //替换结果
case_sensitivity, //大小写是否敏感,默认是1
replace_count); //替换次数
} else if (Z_STRLEN_P(search) > 1) {
Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject),
Z_STRVAL_P(search), Z_STRLEN_P(search),
Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_count);
} else {
MAKE_COPY_ZVAL(subject, result);
}
}
}
到现在为止,我们的目标最终锁定到了php_char_to_str_ex 函数,现在只需要分析这个函数就OK了。其实现为:
复制代码 代码如下:
/* {{{ php_char_to_str_ex
*/
PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_len, zval *result, int case_sensitivity, int * replace_count)
{
int char_count = 0;
int replaced = 0;
char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL;
if (case_sensitivity) { //Now case_sensitivity = 1
char *p = str, *e = p + len;
//Calculate how many times it needs to be replaced
while ((p = memchr(p, from , (e - p)))) {
char_count++;
p++;
}
} else {
for (source = str; source < source_end; source++) {
if (tolower(*source) == tolower(from)) {
char_count++;
}
}
}
if (char_count == 0 && case_sensitivity) {
ZVAL_STRINGL( result, str, len, 1);
return 0;
}
//Calculate the length after replacement and store it in result.
Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
//Apply for memory and store the replaced data
Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
//The setting result is a string
Z_TYPE_P(result) = IS_STRING;
//The values of target and result point to the same block of memory, so only the target
needs to be processed if (case_sensitivity) {
char *p = str, *e = p + len, *s = str;
while ((p = memchr(p, from, (e - p)))) { / /Determine at which character #
memcpy(target, s, (p - s)); //Copy the data before # to target
target += p - s;
memcpy( target, to, to_len); //Copy the target character to target [of course the target at this time starts target+p-s]
target += to_len;
p++;
s = p;
if (replace_count) {
*replace_count += 1; //Set the number of replacements
}
}
//If there is more later, continue to add it to the target, so that the target points to The memory block is already replaced data.
if (s < e) {
memcpy(target, s, (e - s));
target += e - s;
}
} else {
for (source = str; source < source_end; source++) {
if (tolower(*source) == tolower(from)) {
replaced = 1;
if (replace_count) {
*replace_count += 1;
}
for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) {
*target = *tmp;
target++;
}
} else {
*target = *source;
target++;
}
}
}
*target = 0;
return replaced;
}
/* }}} */
As commented above, this completes the replacement of characters into strings. As for how to return and the detailed process, you need to have a relative understanding of the PHP execution process.
Of course, you can use gdb to set a breakpoint to the php_char_to_str_ex function to understand its detailed execution process.
The next article will be about the analysis of replacing strings with strings.
Summary:
The result is stored in zval
The implementation of replacement is quite clever and can be learned.
You need to continue to view the source code and learn more writing skills and design skills.
http://www.bkjia.com/PHPjc/323049.htmlwww.bkjia.comtruehttp: //www.bkjia.com/PHPjc/323049.htmlTechArticlestr_replace — Substring replacement [ str_replace ] mixed str_replace ( mixed $search , mixed $replace , mixed $subject [ , int nbsp; All searches in subject are replaced by replace...