Security update for Core, with self-updated composer
[yaffs-website] / vendor / symfony / finder / Finder.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Finder;
13
14 use Symfony\Component\Finder\Adapter\AdapterInterface;
15 use Symfony\Component\Finder\Adapter\GnuFindAdapter;
16 use Symfony\Component\Finder\Adapter\BsdFindAdapter;
17 use Symfony\Component\Finder\Adapter\PhpAdapter;
18 use Symfony\Component\Finder\Comparator\DateComparator;
19 use Symfony\Component\Finder\Comparator\NumberComparator;
20 use Symfony\Component\Finder\Exception\ExceptionInterface;
21 use Symfony\Component\Finder\Iterator\CustomFilterIterator;
22 use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
23 use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
24 use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
25 use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
26 use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
27 use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
28 use Symfony\Component\Finder\Iterator\SortableIterator;
29
30 /**
31  * Finder allows to build rules to find files and directories.
32  *
33  * It is a thin wrapper around several specialized iterator classes.
34  *
35  * All rules may be invoked several times.
36  *
37  * All methods return the current Finder object to allow easy chaining:
38  *
39  * $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
40  *
41  * @author Fabien Potencier <fabien@symfony.com>
42  */
43 class Finder implements \IteratorAggregate, \Countable
44 {
45     const IGNORE_VCS_FILES = 1;
46     const IGNORE_DOT_FILES = 2;
47
48     private $mode = 0;
49     private $names = array();
50     private $notNames = array();
51     private $exclude = array();
52     private $filters = array();
53     private $depths = array();
54     private $sizes = array();
55     private $followLinks = false;
56     private $sort = false;
57     private $ignore = 0;
58     private $dirs = array();
59     private $dates = array();
60     private $iterators = array();
61     private $contains = array();
62     private $notContains = array();
63     private $adapters = null;
64     private $paths = array();
65     private $notPaths = array();
66     private $ignoreUnreadableDirs = false;
67
68     private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
69
70     public function __construct()
71     {
72         $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
73     }
74
75     /**
76      * Creates a new Finder.
77      *
78      * @return static
79      */
80     public static function create()
81     {
82         return new static();
83     }
84
85     /**
86      * Registers a finder engine implementation.
87      *
88      * @param AdapterInterface $adapter  An adapter instance
89      * @param int              $priority Highest is selected first
90      *
91      * @return $this
92      *
93      * @deprecated since 2.8, to be removed in 3.0.
94      */
95     public function addAdapter(AdapterInterface $adapter, $priority = 0)
96     {
97         @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
98
99         $this->initDefaultAdapters();
100
101         $this->adapters[$adapter->getName()] = array(
102             'adapter' => $adapter,
103             'priority' => $priority,
104             'selected' => false,
105         );
106
107         return $this->sortAdapters();
108     }
109
110     /**
111      * Sets the selected adapter to the best one according to the current platform the code is run on.
112      *
113      * @return $this
114      *
115      * @deprecated since 2.8, to be removed in 3.0.
116      */
117     public function useBestAdapter()
118     {
119         @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
120
121         $this->initDefaultAdapters();
122
123         $this->resetAdapterSelection();
124
125         return $this->sortAdapters();
126     }
127
128     /**
129      * Selects the adapter to use.
130      *
131      * @param string $name
132      *
133      * @return $this
134      *
135      * @throws \InvalidArgumentException
136      *
137      * @deprecated since 2.8, to be removed in 3.0.
138      */
139     public function setAdapter($name)
140     {
141         @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
142
143         $this->initDefaultAdapters();
144
145         if (!isset($this->adapters[$name])) {
146             throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
147         }
148
149         $this->resetAdapterSelection();
150         $this->adapters[$name]['selected'] = true;
151
152         return $this->sortAdapters();
153     }
154
155     /**
156      * Removes all adapters registered in the finder.
157      *
158      * @return $this
159      *
160      * @deprecated since 2.8, to be removed in 3.0.
161      */
162     public function removeAdapters()
163     {
164         @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
165
166         $this->adapters = array();
167
168         return $this;
169     }
170
171     /**
172      * Returns registered adapters ordered by priority without extra information.
173      *
174      * @return AdapterInterface[]
175      *
176      * @deprecated since 2.8, to be removed in 3.0.
177      */
178     public function getAdapters()
179     {
180         @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
181
182         $this->initDefaultAdapters();
183
184         return array_values(array_map(function (array $adapter) {
185             return $adapter['adapter'];
186         }, $this->adapters));
187     }
188
189     /**
190      * Restricts the matching to directories only.
191      *
192      * @return $this
193      */
194     public function directories()
195     {
196         $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
197
198         return $this;
199     }
200
201     /**
202      * Restricts the matching to files only.
203      *
204      * @return $this
205      */
206     public function files()
207     {
208         $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
209
210         return $this;
211     }
212
213     /**
214      * Adds tests for the directory depth.
215      *
216      * Usage:
217      *
218      *   $finder->depth('> 1') // the Finder will start matching at level 1.
219      *   $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
220      *
221      * @param string|int $level The depth level expression
222      *
223      * @return $this
224      *
225      * @see DepthRangeFilterIterator
226      * @see NumberComparator
227      */
228     public function depth($level)
229     {
230         $this->depths[] = new Comparator\NumberComparator($level);
231
232         return $this;
233     }
234
235     /**
236      * Adds tests for file dates (last modified).
237      *
238      * The date must be something that strtotime() is able to parse:
239      *
240      *   $finder->date('since yesterday');
241      *   $finder->date('until 2 days ago');
242      *   $finder->date('> now - 2 hours');
243      *   $finder->date('>= 2005-10-15');
244      *
245      * @param string $date A date range string
246      *
247      * @return $this
248      *
249      * @see strtotime
250      * @see DateRangeFilterIterator
251      * @see DateComparator
252      */
253     public function date($date)
254     {
255         $this->dates[] = new Comparator\DateComparator($date);
256
257         return $this;
258     }
259
260     /**
261      * Adds rules that files must match.
262      *
263      * You can use patterns (delimited with / sign), globs or simple strings.
264      *
265      * $finder->name('*.php')
266      * $finder->name('/\.php$/') // same as above
267      * $finder->name('test.php')
268      *
269      * @param string $pattern A pattern (a regexp, a glob, or a string)
270      *
271      * @return $this
272      *
273      * @see FilenameFilterIterator
274      */
275     public function name($pattern)
276     {
277         $this->names[] = $pattern;
278
279         return $this;
280     }
281
282     /**
283      * Adds rules that files must not match.
284      *
285      * @param string $pattern A pattern (a regexp, a glob, or a string)
286      *
287      * @return $this
288      *
289      * @see FilenameFilterIterator
290      */
291     public function notName($pattern)
292     {
293         $this->notNames[] = $pattern;
294
295         return $this;
296     }
297
298     /**
299      * Adds tests that file contents must match.
300      *
301      * Strings or PCRE patterns can be used:
302      *
303      * $finder->contains('Lorem ipsum')
304      * $finder->contains('/Lorem ipsum/i')
305      *
306      * @param string $pattern A pattern (string or regexp)
307      *
308      * @return $this
309      *
310      * @see FilecontentFilterIterator
311      */
312     public function contains($pattern)
313     {
314         $this->contains[] = $pattern;
315
316         return $this;
317     }
318
319     /**
320      * Adds tests that file contents must not match.
321      *
322      * Strings or PCRE patterns can be used:
323      *
324      * $finder->notContains('Lorem ipsum')
325      * $finder->notContains('/Lorem ipsum/i')
326      *
327      * @param string $pattern A pattern (string or regexp)
328      *
329      * @return $this
330      *
331      * @see FilecontentFilterIterator
332      */
333     public function notContains($pattern)
334     {
335         $this->notContains[] = $pattern;
336
337         return $this;
338     }
339
340     /**
341      * Adds rules that filenames must match.
342      *
343      * You can use patterns (delimited with / sign) or simple strings.
344      *
345      * $finder->path('some/special/dir')
346      * $finder->path('/some\/special\/dir/') // same as above
347      *
348      * Use only / as dirname separator.
349      *
350      * @param string $pattern A pattern (a regexp or a string)
351      *
352      * @return $this
353      *
354      * @see FilenameFilterIterator
355      */
356     public function path($pattern)
357     {
358         $this->paths[] = $pattern;
359
360         return $this;
361     }
362
363     /**
364      * Adds rules that filenames must not match.
365      *
366      * You can use patterns (delimited with / sign) or simple strings.
367      *
368      * $finder->notPath('some/special/dir')
369      * $finder->notPath('/some\/special\/dir/') // same as above
370      *
371      * Use only / as dirname separator.
372      *
373      * @param string $pattern A pattern (a regexp or a string)
374      *
375      * @return $this
376      *
377      * @see FilenameFilterIterator
378      */
379     public function notPath($pattern)
380     {
381         $this->notPaths[] = $pattern;
382
383         return $this;
384     }
385
386     /**
387      * Adds tests for file sizes.
388      *
389      * $finder->size('> 10K');
390      * $finder->size('<= 1Ki');
391      * $finder->size(4);
392      *
393      * @param string|int $size A size range string or an integer
394      *
395      * @return $this
396      *
397      * @see SizeRangeFilterIterator
398      * @see NumberComparator
399      */
400     public function size($size)
401     {
402         $this->sizes[] = new Comparator\NumberComparator($size);
403
404         return $this;
405     }
406
407     /**
408      * Excludes directories.
409      *
410      * @param string|array $dirs A directory path or an array of directories
411      *
412      * @return $this
413      *
414      * @see ExcludeDirectoryFilterIterator
415      */
416     public function exclude($dirs)
417     {
418         $this->exclude = array_merge($this->exclude, (array) $dirs);
419
420         return $this;
421     }
422
423     /**
424      * Excludes "hidden" directories and files (starting with a dot).
425      *
426      * This option is enabled by default.
427      *
428      * @param bool $ignoreDotFiles Whether to exclude "hidden" files or not
429      *
430      * @return $this
431      *
432      * @see ExcludeDirectoryFilterIterator
433      */
434     public function ignoreDotFiles($ignoreDotFiles)
435     {
436         if ($ignoreDotFiles) {
437             $this->ignore |= static::IGNORE_DOT_FILES;
438         } else {
439             $this->ignore &= ~static::IGNORE_DOT_FILES;
440         }
441
442         return $this;
443     }
444
445     /**
446      * Forces the finder to ignore version control directories.
447      *
448      * This option is enabled by default.
449      *
450      * @param bool $ignoreVCS Whether to exclude VCS files or not
451      *
452      * @return $this
453      *
454      * @see ExcludeDirectoryFilterIterator
455      */
456     public function ignoreVCS($ignoreVCS)
457     {
458         if ($ignoreVCS) {
459             $this->ignore |= static::IGNORE_VCS_FILES;
460         } else {
461             $this->ignore &= ~static::IGNORE_VCS_FILES;
462         }
463
464         return $this;
465     }
466
467     /**
468      * Adds VCS patterns.
469      *
470      * @see ignoreVCS()
471      *
472      * @param string|string[] $pattern VCS patterns to ignore
473      */
474     public static function addVCSPattern($pattern)
475     {
476         foreach ((array) $pattern as $p) {
477             self::$vcsPatterns[] = $p;
478         }
479
480         self::$vcsPatterns = array_unique(self::$vcsPatterns);
481     }
482
483     /**
484      * Sorts files and directories by an anonymous function.
485      *
486      * The anonymous function receives two \SplFileInfo instances to compare.
487      *
488      * This can be slow as all the matching files and directories must be retrieved for comparison.
489      *
490      * @return $this
491      *
492      * @see SortableIterator
493      */
494     public function sort(\Closure $closure)
495     {
496         $this->sort = $closure;
497
498         return $this;
499     }
500
501     /**
502      * Sorts files and directories by name.
503      *
504      * This can be slow as all the matching files and directories must be retrieved for comparison.
505      *
506      * @return $this
507      *
508      * @see SortableIterator
509      */
510     public function sortByName()
511     {
512         $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
513
514         return $this;
515     }
516
517     /**
518      * Sorts files and directories by type (directories before files), then by name.
519      *
520      * This can be slow as all the matching files and directories must be retrieved for comparison.
521      *
522      * @return $this
523      *
524      * @see SortableIterator
525      */
526     public function sortByType()
527     {
528         $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
529
530         return $this;
531     }
532
533     /**
534      * Sorts files and directories by the last accessed time.
535      *
536      * This is the time that the file was last accessed, read or written to.
537      *
538      * This can be slow as all the matching files and directories must be retrieved for comparison.
539      *
540      * @return $this
541      *
542      * @see SortableIterator
543      */
544     public function sortByAccessedTime()
545     {
546         $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
547
548         return $this;
549     }
550
551     /**
552      * Sorts files and directories by the last inode changed time.
553      *
554      * This is the time that the inode information was last modified (permissions, owner, group or other metadata).
555      *
556      * On Windows, since inode is not available, changed time is actually the file creation time.
557      *
558      * This can be slow as all the matching files and directories must be retrieved for comparison.
559      *
560      * @return $this
561      *
562      * @see SortableIterator
563      */
564     public function sortByChangedTime()
565     {
566         $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
567
568         return $this;
569     }
570
571     /**
572      * Sorts files and directories by the last modified time.
573      *
574      * This is the last time the actual contents of the file were last modified.
575      *
576      * This can be slow as all the matching files and directories must be retrieved for comparison.
577      *
578      * @return $this
579      *
580      * @see SortableIterator
581      */
582     public function sortByModifiedTime()
583     {
584         $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
585
586         return $this;
587     }
588
589     /**
590      * Filters the iterator with an anonymous function.
591      *
592      * The anonymous function receives a \SplFileInfo and must return false
593      * to remove files.
594      *
595      * @return $this
596      *
597      * @see CustomFilterIterator
598      */
599     public function filter(\Closure $closure)
600     {
601         $this->filters[] = $closure;
602
603         return $this;
604     }
605
606     /**
607      * Forces the following of symlinks.
608      *
609      * @return $this
610      */
611     public function followLinks()
612     {
613         $this->followLinks = true;
614
615         return $this;
616     }
617
618     /**
619      * Tells finder to ignore unreadable directories.
620      *
621      * By default, scanning unreadable directories content throws an AccessDeniedException.
622      *
623      * @param bool $ignore
624      *
625      * @return $this
626      */
627     public function ignoreUnreadableDirs($ignore = true)
628     {
629         $this->ignoreUnreadableDirs = (bool) $ignore;
630
631         return $this;
632     }
633
634     /**
635      * Searches files and directories which match defined rules.
636      *
637      * @param string|array $dirs A directory path or an array of directories
638      *
639      * @return $this
640      *
641      * @throws \InvalidArgumentException if one of the directories does not exist
642      */
643     public function in($dirs)
644     {
645         $resolvedDirs = array();
646
647         foreach ((array) $dirs as $dir) {
648             if (is_dir($dir)) {
649                 $resolvedDirs[] = $dir;
650             } elseif ($glob = glob($dir, (defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
651                 $resolvedDirs = array_merge($resolvedDirs, $glob);
652             } else {
653                 throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
654             }
655         }
656
657         $this->dirs = array_merge($this->dirs, $resolvedDirs);
658
659         return $this;
660     }
661
662     /**
663      * Returns an Iterator for the current Finder configuration.
664      *
665      * This method implements the IteratorAggregate interface.
666      *
667      * @return \Iterator|SplFileInfo[] An iterator
668      *
669      * @throws \LogicException if the in() method has not been called
670      */
671     public function getIterator()
672     {
673         if (0 === count($this->dirs) && 0 === count($this->iterators)) {
674             throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
675         }
676
677         if (1 === count($this->dirs) && 0 === count($this->iterators)) {
678             return $this->searchInDirectory($this->dirs[0]);
679         }
680
681         $iterator = new \AppendIterator();
682         foreach ($this->dirs as $dir) {
683             $iterator->append($this->searchInDirectory($dir));
684         }
685
686         foreach ($this->iterators as $it) {
687             $iterator->append($it);
688         }
689
690         return $iterator;
691     }
692
693     /**
694      * Appends an existing set of files/directories to the finder.
695      *
696      * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
697      *
698      * @param mixed $iterator
699      *
700      * @return $this
701      *
702      * @throws \InvalidArgumentException when the given argument is not iterable
703      */
704     public function append($iterator)
705     {
706         if ($iterator instanceof \IteratorAggregate) {
707             $this->iterators[] = $iterator->getIterator();
708         } elseif ($iterator instanceof \Iterator) {
709             $this->iterators[] = $iterator;
710         } elseif ($iterator instanceof \Traversable || is_array($iterator)) {
711             $it = new \ArrayIterator();
712             foreach ($iterator as $file) {
713                 $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
714             }
715             $this->iterators[] = $it;
716         } else {
717             throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
718         }
719
720         return $this;
721     }
722
723     /**
724      * Counts all the results collected by the iterators.
725      *
726      * @return int
727      */
728     public function count()
729     {
730         return iterator_count($this->getIterator());
731     }
732
733     /**
734      * @return $this
735      */
736     private function sortAdapters()
737     {
738         uasort($this->adapters, function (array $a, array $b) {
739             if ($a['selected'] || $b['selected']) {
740                 return $a['selected'] ? -1 : 1;
741             }
742
743             return $a['priority'] > $b['priority'] ? -1 : 1;
744         });
745
746         return $this;
747     }
748
749     /**
750      * @param $dir
751      *
752      * @return \Iterator
753      */
754     private function searchInDirectory($dir)
755     {
756         if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
757             $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
758         }
759
760         if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
761             $this->notPaths[] = '#(^|/)\..+(/|$)#';
762         }
763
764         if ($this->adapters) {
765             foreach ($this->adapters as $adapter) {
766                 if ($adapter['adapter']->isSupported()) {
767                     try {
768                         return $this
769                             ->buildAdapter($adapter['adapter'])
770                             ->searchInDirectory($dir);
771                     } catch (ExceptionInterface $e) {
772                     }
773                 }
774             }
775         }
776
777         $minDepth = 0;
778         $maxDepth = PHP_INT_MAX;
779
780         foreach ($this->depths as $comparator) {
781             switch ($comparator->getOperator()) {
782                 case '>':
783                     $minDepth = $comparator->getTarget() + 1;
784                     break;
785                 case '>=':
786                     $minDepth = $comparator->getTarget();
787                     break;
788                 case '<':
789                     $maxDepth = $comparator->getTarget() - 1;
790                     break;
791                 case '<=':
792                     $maxDepth = $comparator->getTarget();
793                     break;
794                 default:
795                     $minDepth = $maxDepth = $comparator->getTarget();
796             }
797         }
798
799         $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
800
801         if ($this->followLinks) {
802             $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
803         }
804
805         $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
806
807         if ($this->exclude) {
808             $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
809         }
810
811         $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
812
813         if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
814             $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
815         }
816
817         if ($this->mode) {
818             $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
819         }
820
821         if ($this->names || $this->notNames) {
822             $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
823         }
824
825         if ($this->contains || $this->notContains) {
826             $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
827         }
828
829         if ($this->sizes) {
830             $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
831         }
832
833         if ($this->dates) {
834             $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
835         }
836
837         if ($this->filters) {
838             $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
839         }
840
841         if ($this->paths || $this->notPaths) {
842             $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
843         }
844
845         if ($this->sort) {
846             $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
847             $iterator = $iteratorAggregate->getIterator();
848         }
849
850         return $iterator;
851     }
852
853     /**
854      * @return AdapterInterface
855      */
856     private function buildAdapter(AdapterInterface $adapter)
857     {
858         return $adapter
859             ->setFollowLinks($this->followLinks)
860             ->setDepths($this->depths)
861             ->setMode($this->mode)
862             ->setExclude($this->exclude)
863             ->setNames($this->names)
864             ->setNotNames($this->notNames)
865             ->setContains($this->contains)
866             ->setNotContains($this->notContains)
867             ->setSizes($this->sizes)
868             ->setDates($this->dates)
869             ->setFilters($this->filters)
870             ->setSort($this->sort)
871             ->setPath($this->paths)
872             ->setNotPath($this->notPaths)
873             ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
874     }
875
876     /**
877      * Unselects all adapters.
878      */
879     private function resetAdapterSelection()
880     {
881         $this->adapters = array_map(function (array $properties) {
882             $properties['selected'] = false;
883
884             return $properties;
885         }, $this->adapters);
886     }
887
888     private function initDefaultAdapters()
889     {
890         if (null === $this->adapters) {
891             $this->adapters = array();
892             $this
893                 ->addAdapter(new GnuFindAdapter())
894                 ->addAdapter(new BsdFindAdapter())
895                 ->addAdapter(new PhpAdapter(), -50)
896                 ->setAdapter('php')
897             ;
898         }
899     }
900 }