The explode () function works well when we need to split an array into groups based on a character or string, but do you know how explode () is working? Interception of string problems, will avoid the reallocation of space consumption, explode will also allocate space, no doubt. Old Brand Casino
File 1:ext/standard/string.c//First look at the explode source code 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 to hold the segmented data array_init (return_value);//Because of this, we use the Explode (' | ', '); Become a valid if (Str_len = = 0) {if (limit >= 0) { Add_next_index_stringl (Return_value, "", sizeof ("")-1, 1);} return;} The following two are the original string and the delimiter are built into a _zval_struct structure,//ZVAL_STRINGL will allocate space Oh ~ ~ Source code then posted Zval_stringl (&zstr, str, str_len, 0); Zval_stringl (&zdelim, Delim, Delim_len, 0);//limit value is the third parameter of explode that is allowed to be passed in explode, which allows positive and negative 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);}}
Take another look:
Zval_stringl Source code: //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) ....//_estrndup implementation: Zend/zend_alloc.czend_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); Allocation 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 is an analysis of the call based on the third parameter limit of explode: the condition corresponds to the last three rows in the explode, different from the limit condition. Note: Limit is in the default (not passed), and his default value is Long_max, which is the case of branch 1.
1, limit > 1:
The
Invokes the Php_explode method, which can also be used in the ext/standard/ Found in String.c, and is immediately followed by the explode implementation (so it is convenient to find the method in this function called from this file, almost nothing outside of the function immediately above the upper ^_^).
Phpapi void Php_explode (Zval *delim, Zval *str, Zval *return_value, long limit) {char *p1, *P2, *endp;//first gets the pointer to the end position of the source string en DP = z_strval_p (str) + z_strlen_p (str);//record start position p1 = z_strval_p (str);//The following is the position of the delimiter in Str, You can see that this method is also used in Strrpos and strpos to locate 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 to come out with an array (0 = ' abc ') ADD_NEXT_INDEX_STRINGL (Return_value, p1, z_ Strlen_p (str), 1);} else {//loop to get the position of the next delimiter until the end of Do {//will get the substring (the last position to the middle of this position, the first time the last position is to start Add_next_index_stringl (Return_value, p1, p2 -P1, 1);//Position the location to the delimiter position p2+ the length of the delimiter//For example, delimiter = ' | ', the original string = ' Ab|c ', p2 = 2, then P1=2+1=3p1 = 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 into 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:
Call the Php_explode_negative_limit method:
Phpapi void Php_explode_negative_limit (Zval *delim, Zval *str, Zval *return_value, long limit) {#define Explode_alloc_ste P 64char *p1, *p2, *ENDP;ENDP = z_strval_p (str) + z_strlen_p (str);p 1 = z_strval_p (str);p 2 = php_memnstr (z_strval_p (str), Z _strval_p (Delim), Z_strlen_p (Delim), ENDP); if (P2 = = NULL) {//It is not handled here, then explode (' | ', ' abc ',-1) becomes illegal and cannot get any value/*do Nothing since limit <=-1, thus if only one chunk-1 + (limit) <= 0by doing nothing we return empty array*/} else { int allocated = Explode_alloc_step, found = 0; Long I, To_return;char **positions = emalloc (Allocated * sizeof (char *));//note here the declaration of positions, This array is used to hold the read position of all substrings positions[found++] = p1; Of course the starting position still needs to be saved//below 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 beginning of the array to get the result returned from which SUBSTRING will begin to read 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 check s also for To_return > 0 */add_next_index_stringl (return_value, Positions[i], (positions[i+1]-z_strlen_p (Delim))-Po sitions[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 ');
Add_index_stringl source code//file 4:zend/zend_api.czend_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///is too long, ~ ~ ~
Visible (does not contain allocation space these), when the limit>1, efficiency is O (n) "n is the limit value", when the 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).
To understand PHP's explode () function from the source code