explode関数とimplode関数は、パラメータを取得した後に特定の文字に従って文字列を分割したり、文字列を分割したりするなど、主に文字列と配列間の変換操作に使用されます。配列 結果は、1 つの文字を使用して文字列出力に結合されます。これら 2 つの関数は PHP でよく使用されるため、その原理を理解する必要があります。
この関数は、文字列で構成される配列を返します。各要素は、境界点として文字列 $delimiter で区切られた、文字列の部分文字列です。
制限
$limit が設定されており、それが正の数である場合、返される配列には最大で $limit 要素が含まれ、最後の要素には $string の残りが含まれます。
$limit が負の数の場合、最後の -$limit 要素を除くすべての要素を返します。
$limitが0の場合は1として扱われます。
区切り文字
$delimiter が空の場合、関数は FALSE を返します。区切り文字が文字列内になく、$limit が負の数の場合は、空の配列が返されます。
まずは制限を設けずに状況を見てみましょう
リーリー
limit が正の数の場合、limit は 1 に設定され、最大 1 つの要素が返されます。
リーリー
limit は負の数、limit は -1 で、最後の要素を除くすべての要素が返されます。
リーリー
limit は 0 であり、1 として扱われます。
リーリーexplode 関数のコア実装は php_explode 関数です。以下は、この関数の実行フローチャートです。
if (p2 == NULL) { // 区切り文字が見つからない場合は、文字列全体が直接返されます add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1); } 他 { する { // p1 を return_value 配列に追加します add_next_index_stringl(return_value, p1, p2 - p1, 1); p1 = p2 + Z_STRLEN_P(delim); } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL && -- 制限 > 1); // return_value に最後の値を追加します if (p1 endp) add_next_index_stringl(return_value, p1, endp-p1, 1); } ソースコードの解釈
sizeof("") == 0。 sizeof には、sizeof(typename) と sizeof(expression) の 2 つの用途があります。パラメーターが typename、つまり型名の場合、sizeof は、パラメーターが式の場合、その型に対応するオブジェクトのサイズを返します。 、sizeof は式を計算します。戻り値の型はオブジェクトのサイズに対応します。ここで、"" はコンパイル時にコンパイラによって "" に割り当てられるスペースを計算する式です。 制限が設定されていない場合、制限のデフォルト値は LONG_MAX
です。 php.h ファイルでは、LONG_MAX は 2147483647L として定義されています。実装では、制限が 1 より大きい場合は php_explode
関数が呼び出され、制限が 0 より小さい場合はphp_explode_negative_limit 関数が呼び出されます。 、そして add_index_stringl 関数が呼び出されて、配列 return_value に str が追加されます。 区切り文字を検索する場合、php_memnstr
関数は php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
そしてphp_memnstrはzend_memのマクロ定義ですnstr、内部には zen d_memnstr 実装があるため、文字区切り文字を見つけるために C の memchr が実際に呼び出されます。
セパレータの位置を見つけたら、add_next_index_stringl
爆裂 リーリー
一次元配列の値を文字列に変換しますimplode関数は2つのパラメータオーダーを受け取ることができます。また、最初のパラメータが配列で 2 番目のパラメータが空の場合、2 番目のパラメータはデフォルト値 '' になります。この機能は、爆発の逆のプロセスとみなすことができます。
サンプルを実行する
リーリー
リーリー
最初のパラメータは配列です
リーリー
<p>1、接收参数并赋值<br />2、如果第二个参数为空,则判断第一个参数的类型是否为数组,如果不是,则报错。否则,则使用""对glue赋值,使用其作为连接符。<br />3、如果第二个参数不为空,那么,如果第一个参数是数组类型,则将第二个参数转换成字符串类型;否则,如果第二个参数是数组类型,则将第一个参数转换成字符串类型。<br />4、调用php_implode函数做字符串的连接。</p>
在implode函数设置完参数之后,底层就调用php_implode函数进行字符串连接,php_implode函数的执行流程图如下:
// 遍历数组的每一个元素,判断其类型,然后调用smart_str_appendl函数将值追加到字符串中 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) { switch ((*tmp)->type) { case IS_STRING: smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); break; case IS_LONG: { char stmp[MAX_LENGTH_OF_LONG + 1]; str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp)); smart_str_appendl(&implstr, stmp, str_len); } break; case IS_BOOL: if (Z_LVAL_PP(tmp) == 1) { smart_str_appendl(&implstr, "1", sizeof("1")-1); } break; case IS_NULL: break; case IS_DOUBLE: { char *stmp; str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(tmp)); smart_str_appendl(&implstr, stmp, str_len); efree(stmp); } break; case IS_OBJECT: { int copy; zval expr; zend_make_printable_zval(*tmp, &expr, ©); smart_str_appendl(&implstr, Z_STRVAL(expr), Z_STRLEN(expr)); if (copy) { zval_dtor(&expr); } } break; default: tmp_val = **tmp; zval_copy_ctor(&tmp_val); convert_to_string(&tmp_val); smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); zval_dtor(&tmp_val); break; } // 添加glue字符 if (++i != numelems) { smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim)); } zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos); } // 在尾部添加结束字符0 smart_str_0(&implstr);
php_implode会逐个获取数组里面的内容,然后判断每个元素的类型,再做必要的数据类型转换之后,调用smart_str_appendl函数将值追加到返回的字符串后面。最后,还要在字符串后面加上结束符,这是个必须的操作,以后编程时也应注意。
smart_str_appendl是函数smart_str_appendl_ex的宏定义,该函数调用了memcpy做字符串的复制。
原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
暂且写这么多吧,还有更多的优化和PHP源码中常用的函数,将会在以后的源码阅读中慢慢讲述。
如果本文对你有帮助,请点下推荐吧,谢谢^_^
最后,我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。