When we need to divide an array into groups according to a character or string, explode is very happy, but you know how ~explode works.
The first thing to be sure is that explode will also allocate space, no doubt.
Copy CodeThe code is as follows:
File 1:ext/standard/string.c
First look at the source code of explode
Php_function (Explode)
{
Char *str, *delim;
int str_len = 0, Delim_len = 0;
Long limit = Long_max; /* No Limit */
Zval Zdelim, Zstr;
if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "Ss|l", &delim, &delim_len, &str, &str_len, & limit) = = FAILURE) {
Return
}
if (Delim_len = = 0) {
Php_error_docref (NULL tsrmls_cc, e_warning, "Empty delimiter");
Return_false;
}
This will open an array for storing the segmented data.
Array_init (Return_value);
Because of this, we use explode (' | ', '), and become legal
if (Str_len = = 0) {
if (limit >= 0) {
Add_next_index_stringl (Return_value, "", sizeof ("")-1, 1);
}
Return
}
The following two are constructs the original string and the delimiter to be the _zval_struct structure,
ZVAL_STRINGL will allocate space Oh ~ ~ The source code is then posted
Zval_stringl (&zstr, str, str_len, 0);
Zval_stringl (&zdelim, Delim, Delim_len, 0);
The limit value is the third parameter of the explode that is allowed to be passed in explode, which allows the plus or minus
if (Limit > 1) {
Php_explode (&zdelim, &zstr, Return_value, limit);
} else if (limit < 0) {
Php_explode_negative_limit (&zdelim, &zstr, Return_value, limit);
} else {
Add_index_stringl (return_value, 0, str, str_len, 1);
}
}
Copy CodeThe code is as follows:
Source code for ZVAL_STRINGL:
File 2:zend/zend_api.c
#define ZVAL_STRINGL (z, S, l, duplicate) {\
const char *__s= (s); int __l=l; \
Z_strlen_p (z) = __l; \
Z_strval_p (z) = (duplicate?estrndup (__s, __l):(char*) __s); \
Z_type_p (z) = is_string; \
}
....
Estrndup is the main course:
File 3:zend/zend_alloc.h
#define ESTRNDUP (S, length) _estrndup ((s), (length) zend_file_line_cc zend_file_line_empty_cc)
....
Implementation of _estrndup: ZEND/ZEND_ALLOC.C
ZEND_API Char *_estrndup (const char *s, UINT length zend_file_line_dc zend_file_line_orig_dc)
{
Char *p;
p = (char *) _emalloc (length+1 zend_file_line_relay_cc zend_file_line_orig_relay_cc);
if (unexpected (p = = NULL)) {
return p;
}
memcpy (p, s, length); Allocate space
P[length] = 0;
return p;
}
In addition, the use of zval_string in substr and STRRCHR Strstr is also an application of the appeal.
The following analysis calls are based on the third parameter limit of explode: the condition corresponds to the last three rows in the explode, and the difference between the limit conditions
Note: limit is at default (not passed), his default value is Long_max, which is the case that belongs to branch 1
1, limit > 1:
Call the Php_explode method, which can also be used in ext/standard/ Found in String.c, and is immediately followed by the explode implementation (so it is convenient to find the method called from this file in this function, almost nothing outside of the function immediately above the upper ^_^),
Copy CodeThe code is as follows:
Phpapi void Php_explode (Zval *delim, Zval *str, Zval *return_value, long limit)
{
Char *p1, *P2, *ENDP;
The first is a pointer to the end of the source string.
ENDP = z_strval_p (str) + z_strlen_p (str);
Record start position
P1 = z_strval_p (str);
The following is the position of obtaining the delimiter in STR, which can be seen in Strrpos and Strpos.
P2 = php_memnstr (z_strval_p (str), z_strval_p (Delim), Z_strlen_p (Delim), ENDP);
if (P2 = = NULL) {
Because of this, so when we call explode (' | ', ' abc '), it is legal and comes out of the array (0 = ' abc ')
Add_next_index_stringl (Return_value, p1, Z_strlen_p (str), 1);
} else {
Loop to get the next delimiter position until the end
do {
The resulting substring (the last position to the middle of this position, the first time the last position is the beginning
Add_next_index_stringl (Return_value, p1, P2-P1, 1);
Position the length of the p2+ delimiter to the delimiter position
For example, delimiter = ' | ', original string = ' Ab|c ', p2 = 2, then p1=2+1=3
P1 = p2 + z_strlen_p (delim);
} while ((P2 = Php_memnstr (P1, Z_strval_p (Delim), Z_strlen_p (Delim), ENDP))! = NULL &&
--limit > 1);
Place the string after the last delimiter in the result array
Explode (' | ', ' AVC|SDF '); = = Array (0 = ' AVC ', 1= > ' SDF ')
if (P1 <= ENDP)
Add_next_index_stringl (Return_value, p1, ENDP-P1, 1);
}
}
2, limit < 0:
Calling the Php_explode_negative_limit method
Copy CodeThe code is as follows:
Phpapi void Php_explode_negative_limit (Zval *delim, Zval *str, Zval *return_value, long limit)
{
#define EXPLODE_ALLOC_STEP 64
Char *p1, *P2, *ENDP;
ENDP = z_strval_p (str) + z_strlen_p (str);
P1 = z_strval_p (str);
P2 = php_memnstr (z_strval_p (str), z_strval_p (Delim), Z_strlen_p (Delim), ENDP);
if (P2 = = NULL) {
It has not been handled here, the explode (' | ', ' abc ',-1) is illegal, can not get any value
/*
Do nothing since limit <=-1, thus if only one chunk-1 + (limit) <= 0
By doing nothing we return empty array
*/
} else {
int allocated = Explode_alloc_step, found = 0;
Long I, To_return;
Char **positions = emalloc (Allocated * sizeof (char *));
Notice here that the positions declaration, this array is used to hold the read position of all the sub-strings
positions[found++] = p1; Of course, the starting position still needs to be saved
The following two loops, the first one is to loop all occurrences of the delimiter position in the string and save the next substring read position up
do {
If (found >= allocated) {
Allocated = found + explode_alloc_step;/* Make sure we have enough memory */
positions = Erealloc (positions, allocated*sizeof (char *));
}
positions[found++] = P1 = p2 + z_strlen_p (delim);
} while ((P2 = Php_memnstr (P1, Z_strval_p (Delim), Z_strlen_p (Delim), ENDP)) = NULL);
This is the result of getting the returned results from the array to begin reading from which substring
To_return = limit + found;
/* limit is at least-1 therefore no need of bounds checking:i would be always less than found */
for (i = 0;i < to_return;i++) {/* This checks also for To_return > 0 */
Add_next_index_stringl (Return_value, Positions[i],
(Positions[i+1]-z_strlen_p (Delim))-positions[i],
1
);
}
Efree (positions);//Very important, free memory
}
#undef Explode_alloc_step
}
3, limit = 1 or limit = 0:
When all the first and second conditions are not satisfied, enter this branch, which is very simple to put the source string into the output array, explode (' | ', ' AVC|SD ', 1) or explode (' | ', ' AVC|SD ', 0) will return an array (0 = > ' AVC|SD ');
Copy CodeThe code is as follows:
Add_index_stringl Source Code
File 4:zend/zend_api.c
Zend_api int Add_next_index_stringl (zval *arg, const char *STR, UINT length, int duplicate)/* * {{* * *
{
Zval *tmp;
Make_std_zval (TMP);
ZVAL_STRINGL (TMP, str, length, duplicate);
Return Zend_hash_next_index_insert (Z_arrval_p (ARG), &tmp, sizeof (Zval *), NULL);
}
Zend_hash_next_index_insert
Zend/zend_hash.h
#define ZEND_HASH_NEXT_INDEX_INSERT (HT, PData, ndatasize, pDest) \
_zend_hash_index_update_or_next_insert (HT, 0, PData, ndatasize, PDest, Hash_next_insert zend_file_line_cc)
Zend/zend_hash.c
It's too long ~ ~ ~ ~ ~
is visible (does not contain the allocated space),
When limit>1, the efficiency is O (n) "n is the limit value",
When limit<0, the efficiency is O (n+m) "N is the limit value, M is the number of separator occurrences",
When Limit=1 or limit=0, the efficiency is O (1)
http://www.bkjia.com/PHPjc/324052.html www.bkjia.com true http://www.bkjia.com/PHPjc/324052.html techarticle when we need to divide an array according to a character or string, explode is very happy, but do you know how ~explode works?