为什么“is_file比file_exists快N倍”

首先,写本文的原因是看到番茄的这个 post:http://www.tblog.com.cn/archives/675

我没有重新测试,对于番茄的测试,我觉得绝对靠谱。

But why?

于是打开 php 的代码寻找到了 is_file 和 file_exists 的实现。其实原因简单到让人无法相信!

这两个函数是在 /php-5.2.6/ext/standard/filestat.c 中实现的,代码如下:

1 /* {{{ proto bool is_file(string filename)
2 Returns true if file is a regular file */
3 FileFunction(PHP_FN(is_file), FS_IS_FILE)
4 /* }}} */
5
6 /* {{{ proto bool file_exists(string filename)
7 Returns true if filename exists */
8 FileFunction(PHP_FN(file_exists), FS_EXISTS)
9 /* }}} */

其中的 FileFunction 是一个宏:

1 /* another quickie macro to make defining similar functions easier */
2 #define FileFunction(name, funcnum) \
3 void name(INTERNAL_FUNCTION_PARAMETERS) { \
4 zval **filename; \
5 if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &filename) == FAILURE) { \
6 WRONG_PARAM_COUNT; \
7 } \
8 convert_to_string_ex(filename); \
9 php_stat(Z_STRVAL_PP(filename), (php_stat_len) Z_STRLEN_PP(filename), funcnum, return_value TSRMLS_CC); \
10}

到这个宏为止,还看不出来为什么两个函数会有这么大的差别。关键就在 php_stat 这个函数中。不过这个函数实在太长了,不全贴上来。以 5.2.6 版本代码为例。第 770 行:宏 IS_ACCESS_CHECK 对文件先做了一次检查,也就是 if(type == FS_EXISTS)。如果 type 为 FS_EXISTS 就调用宏 VCWD_ACCESS(virtual_access 函数的包装) 对访问权限进行验证。如果能执行到 919 行时,文件一定是存在的,直接返回 True。
而 is_file 的判断就简单得多,前面的验证一路都是 false 就来到了 913 行,这时调用系统宏 S_ISREG 来判断文件是否存在。

对于 virtual_access() 函数,我了解不多,不过猜测可能需要验证文件的用户权限和组权限,所以操作多过 is_file 的 S_ISREG 宏的验证。

Join the Conversation

6 Comments

  1. 老子很生气,后果很严重……
    没看出来你改了啥。
    呜呼,wordpress 什么时候会有 trac 那种版本控制功能呢?diff 一下就好了……

  2. 教导的是,受到星星大神的启示,偶知道神是怎么批量造人的,男人和女人diff一下,然后patch一下,就可以了

Leave a comment

Your email address will not be published. Required fields are marked *