[Finder] Optimize the hot-path
This commit is contained in:
parent
4a9676b5a2
commit
f156de6b71
|
@ -18,8 +18,10 @@ namespace Symfony\Component\Finder\Iterator;
|
||||||
*/
|
*/
|
||||||
class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
|
class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
|
||||||
{
|
{
|
||||||
|
private $iterator;
|
||||||
private $isRecursive;
|
private $isRecursive;
|
||||||
private $patterns;
|
private $excludedDirs = array();
|
||||||
|
private $excludedPattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -29,10 +31,18 @@ class ExcludeDirectoryFilterIterator extends FilterIterator implements \Recursiv
|
||||||
*/
|
*/
|
||||||
public function __construct(\Iterator $iterator, array $directories)
|
public function __construct(\Iterator $iterator, array $directories)
|
||||||
{
|
{
|
||||||
|
$this->iterator = $iterator;
|
||||||
$this->isRecursive = $iterator instanceof \RecursiveIterator;
|
$this->isRecursive = $iterator instanceof \RecursiveIterator;
|
||||||
$this->patterns = array();
|
$patterns = array();
|
||||||
foreach ($directories as $directory) {
|
foreach ($directories as $directory) {
|
||||||
$this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
|
if (!$this->isRecursive || false !== strpos($directory, '/')) {
|
||||||
|
$patterns[] = preg_quote($directory, '#');
|
||||||
|
} else {
|
||||||
|
$this->excludedDirs[$directory] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($patterns) {
|
||||||
|
$this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($iterator);
|
parent::__construct($iterator);
|
||||||
|
@ -45,12 +55,15 @@ class ExcludeDirectoryFilterIterator extends FilterIterator implements \Recursiv
|
||||||
*/
|
*/
|
||||||
public function accept()
|
public function accept()
|
||||||
{
|
{
|
||||||
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
|
if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
|
||||||
$path = str_replace('\\', '/', $path);
|
return false;
|
||||||
foreach ($this->patterns as $pattern) {
|
}
|
||||||
if (preg_match($pattern, $path)) {
|
|
||||||
return false;
|
if ($this->excludedPattern) {
|
||||||
}
|
$path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
|
||||||
|
$path = str_replace('\\', '/', $path);
|
||||||
|
|
||||||
|
return !preg_match($this->excludedPattern, $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -58,13 +71,14 @@ class ExcludeDirectoryFilterIterator extends FilterIterator implements \Recursiv
|
||||||
|
|
||||||
public function hasChildren()
|
public function hasChildren()
|
||||||
{
|
{
|
||||||
return $this->isRecursive && $this->getInnerIterator()->hasChildren();
|
return $this->isRecursive && $this->iterator->hasChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getChildren()
|
public function getChildren()
|
||||||
{
|
{
|
||||||
$children = new self($this->getInnerIterator()->getChildren(), array());
|
$children = new self($this->iterator->getChildren(), array());
|
||||||
$children->patterns = $this->patterns;
|
$children->excludedDirs = $this->excludedDirs;
|
||||||
|
$children->excludedPattern = $this->excludedPattern;
|
||||||
|
|
||||||
return $children;
|
return $children;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,11 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||||
*/
|
*/
|
||||||
private $rewindable;
|
private $rewindable;
|
||||||
|
|
||||||
|
// these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
|
||||||
|
private $rootPath;
|
||||||
|
private $subPath;
|
||||||
|
private $directorySeparator = '/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -48,6 +53,10 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||||
|
|
||||||
parent::__construct($path, $flags);
|
parent::__construct($path, $flags);
|
||||||
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
|
$this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
|
||||||
|
$this->rootPath = (string) $path;
|
||||||
|
if ('/' !== DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
|
||||||
|
$this->directorySeparator = DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +66,17 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||||
*/
|
*/
|
||||||
public function current()
|
public function current()
|
||||||
{
|
{
|
||||||
return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
|
// the logic here avoids redoing the same work in all iterations
|
||||||
|
|
||||||
|
if (null === $subPathname = $this->subPath) {
|
||||||
|
$subPathname = $this->subPath = (string) $this->getSubPath();
|
||||||
|
}
|
||||||
|
if ('' !== $subPathname) {
|
||||||
|
$subPathname .= $this->directorySeparator;
|
||||||
|
}
|
||||||
|
$subPathname .= $this->getFilename();
|
||||||
|
|
||||||
|
return new SplFileInfo($this->rootPath.$this->directorySeparator.$subPathname, $this->subPath, $subPathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +92,10 @@ class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
|
||||||
if ($children instanceof self) {
|
if ($children instanceof self) {
|
||||||
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
|
// parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
|
||||||
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
|
$children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
|
||||||
|
|
||||||
|
// performance optimization to avoid redoing the same work in all children
|
||||||
|
$children->rewindable = &$this->rewindable;
|
||||||
|
$children->rootPath = $this->rootPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $children;
|
return $children;
|
||||||
|
|
Reference in New Issue