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 には、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源码注解。