str_replace -substring substitution [str_replace]
Mixed Str_replace (mixed $search, mixed $replace, mixed $subject [, int & $count])
php function str_replace: Returns a string or array. The string or array is the result of replacing all search in subject with replace.
Now we can know some of the uses of this function, such as: Str_replace ("#", "-", "dizaz#7#final"), Str_replace (Array (' # ', ' $ '), "-", "dizaz#7$final"), etc., In terms of these invocation methods, how does PHP work internally, given the [deep understanding of the PHP kernel], where the analysis is small.
Test code:
Copy CodeThe code is as follows:
<?php
$object = "Dizaz#7#final";
$res = Str_replace ("#", "-", $object);
Echo $res;
As above, replace the character "#" with the character "-" first.
Preparatory work:
Download PHP source code, http://www.php.net download can be
Create your own reading code tools [I use Vim+cscope] Another: Linux users also recommend a graphical view of the source code tool Kscope [Google]
compilation tools [GCC], debugging tools [GDB], another: GdB graphical port ddd is also very good, recommended
Compile PHP source code, remember to use--enable-debug [certainly also want to pass./configure--help Look at some of the compilation options provided by PHP, there will be a lot of gains]
Start Analysis:
Reading with the [deep understanding of the PHP kernel], it's not hard to find that PHP provides the standard functions in the directory of the Php-source-dir/ext/standard directory, because it is a string function, it is easy for us to find in this directory Str_replace function implementation of the file STRING.C, followed by an analysis of the file. [Of course with cscope can easily be locked, with: CS find S Str_replace]
The query learns that its definition is implemented:
Copy CodeThe code is as follows:
/* {{{proto mixed str_replace (mixed search, mixed replace, mixed subject [, int &replace_count])
Replaces all occurrences the search in haystack with replace/
Php_function (Str_replace)
{
Php_str_replace_common (Internal_function_param_passthru, 1);
}
/* }}} */
Now you need to see the function Php_str_replace_common function
Copy CodeThe code is as follows:
/* {{{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, "ZZZZ", &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) {
..//Code province filter
else {/* If subject isn't 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);
}
}
/* }}} */
Continue tracking Php_str_replace_in_subject
Copy CodeThe code is as follows:
/* {{{Php_str_replace_in_subject
*/
static void Php_str_replace_in_subject (Zval *search, Zval *replace, Zval **subject, zval *result, int case_sensitivity, in T *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) {
.//Don't take this step
} else {
if (z_strlen_p (search) = = 1) {//The example only "#" So, perform this step.
PHP_CHAR_TO_STR_EX (z_strval_pp (subject),//subject value, that is, dizaz#7#final
Z_STRLEN_PP (subject),//Get the length of subject
Z_strval_p (search) [0],//due to only 1 "#", so only the first character
Z_strval_p (replace),//the character to be replaced, is now "-"
Z_strlen_p (replace),//target character length, now 1
result,//Replace results
Case_sensitivity,//Case sensitivity, default is 1
Replace_count); Number of replacements
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);
}
}
}
So far, our goal has finally locked into the PHP_CHAR_TO_STR_EX function, and now it's OK to just parse the function. In fact, the present is:
Copy CodeThe code is as follows:
/* {{{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, in T *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;
Calculation needs to be replaced several times
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;
}
Calculates the length after substitution and is stored in result.
Z_strlen_p (Result) = Len + (Char_count * (to_len-1));
application memory, storing 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;
Target and result values all point to the unified block memory, so you only have to deal with Target
if (case_sensitivity) {
char *p = str, *e = p + len, *s = str;
while (P = MEMCHR (P, from, (e-p))) {//judgment in the first few characters appear #
memcpy (Target, S, (p-s)); Copy the previous data from the # to target.
Target + = P-s;
memcpy (target, to, To_len); Copy the target characters to target[of course the target at this point is starting target+p-s.
Target + = To_len;
p++;
s = p;
if (Replace_count) {
*replace_count + 1; Set the number of replacements
}
}
If you continue to add to target after that, the memory block that target points to is already a replacement for good 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 noted above, it completes the substitution of characters to strings. As for how to return, how a detailed process, need to have a relatively understanding of the PHP implementation process.
Of course, you can use gdb down breakpoint to php_char_to_str_ex function, to understand its detailed implementation process.
Next to do the analysis for strings to be replaced with strings.
Summary:
The result is the existence of Zval
The implementation of the replacement is more ingenious, can learn
Need to continue to view the source code, learn more writing techniques and design techniques.