Finder组件

3.4 版本
维护中的版本

Finder组件通过一个直观而流畅的接口来寻找文件和目录。

安装 

你可以通过下述两种方式安装:

然后,包容vendor/autoload.php文件,以开启Composer提供的自动加载机制。否则,你的程序将无法找到这个Symfony组件的类。

用法 

Finder 寻找文件和/或目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Finder\Finder;
 
$finder = new Finder();
$finder->files()->in(__DIR__);
 
foreach ($finder as $file) {
    // Dump the absolute path / 剥离出绝对路径
    var_dump($file->getRealPath());
 
    // Dump the relative path to the file, omitting the filename
    // 剥离出文件的相对路径,忽略文件名
    var_dump($file->getRelativePath());
 
    // Dump the relative path to the file
    // 剥离出文件的相对路径
    var_dump($file->getRelativePathname());
}

$fileSplFileInfo 的一个实例,它继承了PHP自己的 SplFileInfo 以提供能够处理相对路径的方法。

上面代码递归地输出当前目录下的全部文件名。Finder类使用了fluent接口,因此所有方法返回的都是Finder实例。

一个Finder实例是一个PHP Iterator。所以,不同于使用 foreach 来遍历Finder,你应该使用 iterator_to_array 方法把它转换成数组,或是使用 iterator_count 来取得item数量。

当要搜索多个位置并将它们传入 in() 方法时,程序内部会为每个位置创建一个独立的迭代器。由于 iterator_to_array 默认使用了结果数组的键,当转换成一个数组时,某些键可能会重复,它们的值会被覆写。将 false 作为第二参数传入 iterator_to_array 可以避免此种情况。

标准 

组件提供多种方式对你的结果进行过滤和归类。

位置 

location(位置)是唯一的强制项。它告诉finder要使用哪个目录进行搜索。

1
$finder->in(__DIR__);

通过链式调用(chaining calls)in() 可以在若干位置进行搜索:

1
2
3
4
5
// search inside *both* directories / *两个* 目录中都会搜索
$finder->files()->in(array(__DIR__, '/elsewhere'));
 
// same as above / 效果同上
$finder->in(__DIR__)->in('/elsewhere');

使用通配符可在“pattern匹配”的目录中进行搜索:

1
$finder->in('src/Symfony/*/*/Resources');

每个pattern至少会解析一个目录路径。

匹配时若要排除目录可以使用 exclude() 方法:

1
$finder->in(__DIR__)->exclude('ruby');

对目录没有读取权限时也可以忽略此目录:

1
$finder->ignoreUnreadableDirs()->in(__DIR__);

由于Finder使用的是PHP迭代器,你可以传入任何支持 protocol 的URL:

1
$finder->in('ftp://example.com/pub/');

Finder也可以和用户自定义的streams一起工作:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Finder\Finder;
 
$s3 = new \Zend_Service_Amazon_S3($key, $secret);
$s3->registerStreamWrapper('s3');
 
$finder = new Finder();
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
foreach ($finder->in('s3://bucket-name') as $file) {
    // ... do something with the file / 对文件进行处理
}

阅读 Streams 文档以了解如何创建你自己的流。

文件和目录 

默认时,Finder返回文件和目录;但是 files()directories() 方法分别控制之:

1
2
3
$finder->files();
 
$finder->directories();

如果你要跟随链接,使用 followLinks() 方法:

1
$finder->files()->followLinks();

默认时,iterator会忽略常见的VCS文件。使用 ignoreVCS() 方法即可改变此种行为:

1
$finder->ignoreVCS(false);

归类 

搜索结果根据(文件/目录的)name和type进行归类(目录在先,然后是文件):

1
2
3
$finder->sortByName();
 
$finder->sortByType();

注意 sort* 方法需要得到所有匹配的元素才能完成工作。对于巨大的iterators,它会非常慢。

你也可以定义自己的 sort() 方法:

1
2
3
4
5
6
$sort = function (\SplFileInfo $a, \SplFileInfo $b)
{
    return strcmp($a->getRealPath(), $b->getRealPath());
};
 
$finder->sort($sort);

文件名 

要通过文件名来限制文件,使用 name() 方法:

1
$finder->files()->name('*.php');

name() 方法接收globs(通配符),字符串,或是regexes(正则表达式):

1
$finder->files()->name('/\.php$/');

notName() 方法可以排除匹配到pattern的文件:

1
$finder->files()->notName('*.rb');

文件内容 

要通过内容来限制文件,使用 contains() 方法:

1
$finder->files()->contains('lorem ipsum');

contains() 方法接收字符串,或是regexes(正则表达式):

1
$finder->files()->contains('/lorem\s+ipsum$/i');

notContains() 方法可以排除匹配到给定pattern的文件:

1
$finder->files()->notContains('dolor sit amet');

路径 

要通过Path(路径)来限制文件,使用 path() 方法:

1
2
3
4
5
6
// matches files that contain "data" anywhere in their paths (files or directories)
// 匹配那些路径中包含有“data”的文件(或目录)
$finder->path('data');
// for example this will match data/*.xml and data.xml if they exist
// 例如,这将匹配 data/*.xml 以及 data.xml,如果存在的话
$finder->path('data')->name('*.xml');

在所有平台上,斜杠(/)应被当作目录分隔符来使用。

path() 方法接收一个字符串或者一个正则表达式:

1
2
$finder->path('foo/bar');
$finder->path('/^foo\/bar/');

在内部,字符串会被进行斜杠转义并添加分隔符,然后转换成正则表达式:

1
2
dirname    ===>    /dirname/
a/b/c      ===>    /a\/b\/c/

notPath() 方法根据路径来排除文件:

1
$finder->notPath('other/dir');

文件大小 

要通过大小来限制文件,使用 size() 方法:

1
$finder->files()->size('< 1.5K');

通过链式调用来限制文件的容量范围:

1
$finder->files()->size('>= 1K')->size('<= 2K');

比较运算符可以是以下任意一种:>, >=, <, <=, ==, !=

目标值可以使用“量级”单位,KB (k, ki), MB (m, mi), 或GB (g, gi)。那些使用了 i 后缀的单位,用的是专业的 2**n 版本,遵照 IEC standard

文件日期 

要通过“最后修改日期”来限制文件,使用 date() 方法:

1
$finder->date('since yesterday');

比较运算符可以是以下任意一种:>, >=, <, <=, ==。你也可以使用 sinceafter 作为 >, 和 until 的假名,或者用 before 作为 <的假名。

目标值可以使用任何支持 strtotime 函数的日期格式。

目录层数 

默认时,Finder递归地遍历目录。要限制遍历的目录层数,使用 depth()

1
2
$finder->depth('== 0');
$finder->depth('< 3');

自定义过滤 

要通过你自己的策略来限制匹配到的文件,使用 filter()

1
2
3
4
5
6
7
8
$filter = function (\SplFileInfo $file)
{
    if (strlen($file) > 10) {
        return false;
    }
};
 
$finder->files()->filter($filter);

filter() 方法接收一个 Closure 作为参数。文件的每一次匹配,它都会被调用,其参数文件将作为 SplFileInfo 实例。如果Closure返回 false,则文件将被排除出结果集。

读取返回文件的内容 

返回文件的内容可以通过 getContents() 来读取:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Finder\Finder;
 
$finder = new Finder();
$finder->files()->in(__DIR__);
 
foreach ($finder as $file) {
    $contents = $file->getContents();
 
    // ...
}

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)