pupuk / blog

My New Blog. Record & Share. Focus on PHP, MySQL, Javascript and Golang.
MIT License
9 stars 2 forks source link

一次无聊的is_file, is_dir和file_exists性能测试和原因分析 #16

Open pupuk opened 5 years ago

pupuk commented 5 years ago

在PHP中,判断一个文件或者目录是否存在我们可以使用 file_exists函数

file_exists ( string $filename ) : bool

如果我们知道我们要判断的是,一个文件或者一个目录,就可以使用更具体的函数is_file或者is_dir

is_file ( string $filename ) : bool is_dir ( string $filename ) : bool

据说这样可以有更高的效率,当然我们可以感性的认识,is_file和is_dir做的事情更具体,所以快,file_exists做的事情更多,要考虑的情况更多,可能就会慢些。今天快放假了,干脆做一个测试,在看看源码。

php -v
PHP 7.3.1 (cli) (built: Jan  8 2019 13:55:51) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.1, Copyright (c) 1999-2018, by Zend Technologies
ll test.data
-rwxrwx--- 1 root vboxsf 1.0G Jan 24 15:05 test.data

image

环境为:PHP7.3.1 cli 不开opcache,Centos7.6 2Core 4G 循环100w次,不过次代码中,不管循环多少次,解析php的源码本身只需要一次,所以开不开opcache对结果无多大影响

file_exists 100w 次 image

is_file 100w 次 image image 果然差距明显

pupuk commented 5 years ago

源码分析

搜索PHP7.3.1源码相关is_file 的内容 ext/standard/basic_functions.c中 PHP_FE(is_file, arginfo_is_file) 其中arginfo_is_file是控制参数用的,在此处被定义

ZEND_BEGIN_ARG_INFO(arginfo_is_file, 0)
    ZEND_ARG_INFO(0, filename)
ZEND_END_ARG_INFO()

在ext/standard/php_filestat.h中定义了PHP FUNCTION PHP_FUNCTION(is_file); 在其对应的ext/standard/php_filestat.c文件中定义具体的实现 image

在同样的文件中

       case FS_IS_W:
        RETURN_BOOL((ssb.sb.st_mode & wmask) != 0);
    case FS_IS_R:
        RETURN_BOOL((ssb.sb.st_mode&rmask)!=0);
    case FS_IS_X:
        RETURN_BOOL((ssb.sb.st_mode&xmask)!=0);
    case FS_IS_FILE:
        RETURN_BOOL(S_ISREG(ssb.sb.st_mode));
    case FS_IS_DIR:
        RETURN_BOOL(S_ISDIR(ssb.sb.st_mode));
    case FS_IS_LINK:
        RETURN_BOOL(S_ISLNK(ssb.sb.st_mode));
    case FS_EXISTS:
        RETURN_TRUE; /* the false case was done earlier */
    case FS_LSTAT:
        /* FALLTHROUGH */
    case FS_STAT:
        array_init(return_value);

        ZVAL_LONG(&stat_dev, stat_sb->st_dev);
        ZVAL_LONG(&stat_ino, stat_sb->st_ino);
        ZVAL_LONG(&stat_mode, stat_sb->st_mode);
        ZVAL_LONG(&stat_nlink, stat_sb->st_nlink);
        ZVAL_LONG(&stat_uid, stat_sb->st_uid);
        ZVAL_LONG(&stat_gid, stat_sb->st_gid);