Str_replace - Substring replacementPipeline [Str_replace]
Mixed Str_replace(Mixed $ Search , Mixed $ Replace , Mixed $ Subject[,Int&$ Count])
Php FunctionsStr_replace: Returns a string or array. This string or array is Subject All Search Are Replace Result After replacement.
The usage of this function, such as str_replace ("#", "-", "dizaz #7 # final"), str_replace (array ('#', '$'), "-", "dizaz #7 $ final"), and so on, how are php internal implementation of these calling methods? In view of [a deep understanding of the PHP kernel], here is a small analysis.
Test code:
Copy codeThe Code is as follows:
<? Php
$ Object = "dizaz #7 # final ";
$ Res = str_replace ("#", "-", $ object );
Echo $ res;
First, replace the character "#" with the character.
Preparations:
Download PHP source code, http://www.php.net download
Build your own code-reading tool [I use VIM + cs.pdf]. In addition, Linux users are recommended to view the source code tool in a graphical way. kscope [google]
Compilation tool [gcc], debugging tool [gdb], and GDB graphical port DDD are also very good, recommended
Compile the PHP source code. Remember to use -- enable-debug [Of course, you also hope to use./configure -- help to check some of the compilation options provided by PHP. There will be a lot of GAINS]
Start analysis:
Through [a deep understanding of the PHP kernel] reading, it is not difficult to find that its PHP provides the standard function directory for the PHP-SOURCE-DIR/ext/standard directory, because it is a string function, it is easy to find the string file implemented by the str_replace function in this directory. c. Analyze the file. [Of course, it is easy to lock with cssag, and use: cs find s str_replace]
Query to learn its definition implementation:
Copy codeThe Code is as follows:
/* {Proto mixed str_replace (mixed search, mixed replace, mixed subject [, int & replace_count])
Replaces all occurrences of search in haystack with replace */
PHP_FUNCTION (str_replace)
{
Php_str_replace_common (INTERNAL_FUNCTION_PARAM_PASSTHRU, 1 );
}
/*}}}*/
Now you need to check the 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_sensiti.pdf)
{
/**
* TODO
* Typedef struct _ zval_struct zval;
* Typedef struct _ 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 re dealing with strings and do the replacement .*/
If (Z_TYPE_PP (search )! = IS_ARRAY ){
... // Save the code Filter
} Else {/* if subject is not an array */
Php_str_replace_in_subject (* search, * replace, subject, return_value, case_sensiti.pdf, (argc> 3 )? & Count: NULL );
}
If (argc> 3 ){
Zval_dtor (* zcount );
ZVAL_LONG (* zcount, count );
}
}
/*}}}*/
Continue tracing 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_sensiti.pdf, 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 ){
... // Skip this step
} Else {
If (Z_STRLEN_P (search) = 1) {// only "#" in the example. Therefore, perform this step.
Php_char_to_str_ex (Z_STRVAL_PP (subject), // The value of subject, that is, dizaz #7 # final
Z_STRLEN_PP (subject), // get the length of subject
Z_STRVAL_P (search) [0], // because there is only one "#", only the first character is required.
Z_STRVAL_P (replace), // the character to be replaced, which is "-"
Z_STRLEN_P (replace), // The length of the target character, which is now 1
Result, // Replace the result
Case_sensiti.pdf, // case sensitivity. The default value is 1.
Replace_count); // Number of replicas
} 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_sensiti.pdf, replace_count );
} Else {
MAKE_COPY_ZVAL (subject, result );
}
}
}
So far, our goal has finally been locked to the php_char_to_str_ex function. Now we only need to analyze this function and it will be OK. Its implementation is as follows:
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_sensiti.pdf, int * replace_count)
{
Int char_count = 0;
Int replaced = 0;
Char * source, * target, * tmp, * source_end = str + len, * tmp_end = NULL;
If (case_sensiti.pdf) {// now case_sensiti.pdf = 1
Char * p = str, * e = p + len;
// The number of times the calculation 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_sensiti.pdf ){
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 to store the replaced data
Z_STRVAL_P (result) = target = safe_emalloc (char_count, to_len, len + 1 );
// Set the result to a string
Z_TYPE_P (result) = IS_STRING;
// The values of target and result all point to the unified block memory, so you only need to process the target
If (case_sensiti.pdf ){
Char * p = str, * e = p + len, * s = str;
While (p = memchr (p, from, (e-p) {// judge the number of characters that appear #
Memcpy (target, s, (p-s); // copy # previous data to target
Target + = p-s;
Memcpy (target, to, to_len); // copy the target character to the target. [of course, the target starts with target + p-s]
Target + = to_len;
P ++;
S = p;
If (replace_count ){
* Replace_count + = 1; // set the number of replicas.
}
}
// If there are other memory blocks, add them to the target, so that the memory block pointed to by the target is already replaced.
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 mentioned above, it completes replacement of characters to strings. As for how to return and how to perform a detailed process, you need to have a relative understanding of the PHP Execution Process.
Of course, you can use the gdb breakpoint To Go To The php_char_to_str_ex function to learn the detailed execution process.
In the next article, we will analyze how to replace a string with a string.
Summary:
The result is in zval.
Its implementation of replacement is clever and can be learned.
You need to continue to view the source code and learn more writing skills and design skills.