作者归档:admin

PHP源码阅读笔记三:strrchr, strstr, stristr函数

PHP源码阅读笔记三:strrchr, strstr, stristr函数

string strrchr ( string haystack, string needle )
返回haystack中最后一个needle(字符)所在位置以后的字符串
如果needle为数字,将这个数字转化为这个值所对应的字符
如果needle多于一个字符串,则取第一个字符
如果haystack为一个数字,会将这个数字直接转化成字符串
程序中调用convert_to_string_ex(haystack);

在此函数的实现中,基本上是对一些特殊情况的处理(如上),
到最后就是定位最后一个needle出现的位置,返回根据位置返回此位置以后的字符串,如果此位置不存在,同返回false

string strstr ( string haystack, string needle )
此函数功能与strrchr类似,只不过它的needle允许为字符串,并且是查找needle第一个出现的位置,根据此位置返回之后的字符串,如果不存在则返回FALSE

在其代码中有一些特别的细节值得学习,如下所示代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static inline char *zend_memnstr(char *haystack, char *needle, int needle_len, char *end)
{
    char *p = haystack;
    char ne = needle[needle_len-1];
 
    if(needle_len > end-haystack) {
        return NULL;
    }
    end -= needle_len;   //    优化细节一,仅查找end-needle_len长度的字符串
 
    while (p <= end) {
        //    优化细节二,此处先判断字符串的开头和结尾的字符是否一样,如果一样则再判断整个字符串,提升性能
        if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {    
            if (!memcmp(needle, p, needle_len-1)) {
                return p;
            }
        }
 
        if (p == NULL) {
            return NULL;
        }
 
        p++;
    }
 
    return NULL;
}

以上代码是strstr和stristr函数实现的核心代码,功能:查找needle在haystack中首次出现的位置

string stristr ( string haystack, string needle )
stristr函数的功能与strstr类似,所不同的是其不区分大小写。
在PHP源码实现中主要区别是添加了将所有字符串转化为小写的操作,程序实现是在查找之前添加了如下代码:

1
2
3
php_strtolower(s, s_len);
php_strtolower(t, t_len);
return php_memnstr(s, t, t_len, s + s_len);

PS:在看源码的过程中,再次看了《再再认指针》的前面一段话,多了一些体会;
指针能够进行加减法,原因并不是因为它是指针,加减法则不是属于指针这种变量的,而是地址这种数据类型的本能,正是因为地址具有加减的能力,所以才使指针作为存放地址的变量能够进行加减运算。
这跟整数变量因为整数能够进行加减乘除因而它也能进行加减乘除一个道理。
查看《再再论指针》,请猛击再再论指针

PHP源码阅读笔记二:strlen, strtolower, strtoupper, ord, chr函数

PHP源码阅读笔记二:strlen, strtolower, strtoupper, ord, chr函数

int strlen ( string string )
返回字符串的长度
在标准扩展中并没有相关的实现,在其它扩展函数中使用Z_STRLEN、Z_STRLEN_P或Z_STRLEN_PP取得长度

string strtolower ( string str )
将一个字符串变为小写,其实现如下代码
【经典源代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
char *php_strtolower(char *s, size_t len)
{
              unsigned char *c, *e;
 
              c = s;
              e = c+len;
 
              while (c < e) {
                            *c = tolower(*c);
                            c++;
              }
              return s;
}

这虽然是一个简单的遍历字符串并将每个字符变为小写的程序,但是这是一个使用指针的标程。

string strtoupper ( string string )
将一个字符串变为大写
代码实现与上面的程序类似只是将tolower函数变成了toupper
string chr ( int ascii )
返回相对应于 ascii 所指定的单个字符。
其本质是返回一个长度为1的字符串
【源代码】

1
2
3
              temp[0] = (char) Z_LVAL_PP(num);
              temp[1] = 0;
              RETVAL_STRINGL(temp, 1, 1);

int ord ( string string )
返回字符的ASCII值
其本质上是返回字符串第一个字符的ASCII值
【源代码】

1
RETURN_LONG((unsigned char) Z_STRVAL_PP(str)[0]);

PHP源码阅读笔记一:explode和implode函数

PHP源码阅读笔记一
一、explode和implode函数
array explode ( string separator, string string [, int limit] )
此函数返回由字符串组成的数组,每个元素都是 string 的一个子串,它们被字符串 separator 作为边界点分割出来。如果设置了 limit 参数,则返回的数组包含最多 limit 个元素,而最后那个元素将包含 string 的剩余部分。

此函数的时间复杂度应该是O(strlen(separator) * strlen(string))
其实现过程基本上是遍历字符串string,将它与separator比较,如果相同,则写入hash表,并将string的指针移到新的位置(即每一个separator的右边);

另外,对于limit小于0的情况有特殊处理
本函数实现主要是依赖于php_memnstr函数,在php.h文件中我们可以看到它的定义,
#define php_memnstr zend_memnstr
其真正的函数是zend_memnstr,在Zend/zend_operators.h文件的217行,可以看到它的定义,其实现主要是一个while循环和两个C语言的函数memchr和memcmp

string implode ( string glue, array pieces )
此函数返回一个以glue字符串连接的pieces数组的各元素的字符串。
此函数可以是以一个数组为参数,可以是以一个数组和一个字符串为参数,并且字符串和数组的顺序可以改变,这些在程序中都有针对每种情况的特殊处理,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
              if (argc == 1) {
                            if (Z_TYPE_PP(arg1) != IS_ARRAY) {                            //              只有一个参数并且还不是数组
                                          php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument must be an array");
                                          return;
                            }
 
                            MAKE_STD_ZVAL(delim);
#define _IMPL_EMPTY ""
                            ZVAL_STRINGL(delim, _IMPL_EMPTY, sizeof(_IMPL_EMPTY) - 1, 0);
 
                            SEPARATE_ZVAL(arg1);
                            arr = *arg1;
              } else {              //              两个参数
                            if (Z_TYPE_PP(arg1) == IS_ARRAY) {              //              如果每一个参数是数组
                                          arr = *arg1;
                                          convert_to_string_ex(arg2);
                                          delim = *arg2;
                            } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {              //              如果第二个参数是数组
                                          arr = *arg2;
                                          convert_to_string_ex(arg1);
                                          delim = *arg1;
                            } else {
                                          php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments passed");
                                          return;
                            }
              }

最后数组都会赋值给arr,分隔字符串赋值给delim,没有的置为””

就是一个遍历数组,并连接字符串的过程,只是这个过程中使用了smart_str相关函数(更多相关请移步 ),针对不同的类型作了不同的连接操作(如果是数字还需要将数字转化成字符串,这些在smart_str中都有相关函数处理)