Skip to content

Commit 4b91c3b

Browse files
committed
Use RecursiveDirectoryIterator instead of scandir().
1 parent f02eca3 commit 4b91c3b

File tree

3 files changed

+38
-68
lines changed

3 files changed

+38
-68
lines changed

src/NamespaceDirectory.php

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -534,21 +534,23 @@ public function getIterator(): \Iterator {
534534
public function getElements(): array {
535535
$classes = [];
536536
$subdirs = [];
537-
foreach ($this->scanThisDir() as $candidate) {
538-
if (!preg_match(self::CANDIDATE_REGEX, $candidate, $m)) {
539-
continue;
540-
}
541-
[, $name, $ext] = $m;
542-
$path = $this->directory . '/' . $candidate;
543-
if ($ext) {
544-
if (is_file($path)) {
545-
$classes[$path] = $this->terminatedNamespace . $name;
537+
foreach (NsDirUtil::getDirContents($this->directory) as $candidate => $is_dir) {
538+
if (!$is_dir) {
539+
if (!\str_ends_with($candidate, '.php')) {
540+
continue;
541+
}
542+
$path = $this->directory . '/' . $candidate;
543+
$name = \substr($candidate, 0, -4);
544+
if (!\preg_match(self::CLASS_NAME_REGEX, $name)) {
545+
continue;
546546
}
547+
$classes[$path] = $this->terminatedNamespace . $name;
547548
}
548549
else {
549-
if (is_dir($path)) {
550-
$subdirs[$candidate] = $this->subdir($candidate);
550+
if (!\preg_match(self::CLASS_NAME_REGEX, $candidate)) {
551+
continue;
551552
}
553+
$subdirs[$candidate] = $this->subdir($candidate);
552554
}
553555
}
554556
/** @var array<string, class-string> $classes */
@@ -560,16 +562,11 @@ public function getElements(): array {
560562
*/
561563
public function getClassFilesHere(): array {
562564
$classFiles = [];
563-
foreach ($this->scanThisDir() as $candidate) {
564-
if ('.' === $candidate[0]
565-
|| !\str_ends_with($candidate, '.php')
566-
) {
565+
foreach (NsDirUtil::getDirContents($this->directory) as $candidate => $is_dir) {
566+
if ($is_dir || !\str_ends_with($candidate, '.php')) {
567567
continue;
568568
}
569569
$path = $this->directory . '/' . $candidate;
570-
if (!\is_file($path)) {
571-
continue;
572-
}
573570
$name = \substr($candidate, 0, -4);
574571
if (!\preg_match(self::CLASS_NAME_REGEX, $name)) {
575572
continue;
@@ -584,31 +581,12 @@ public function getClassFilesHere(): array {
584581
* @return \Iterator<string, static>
585582
*/
586583
public function getSubdirsHere(): \Iterator {
587-
foreach ($this->scanThisDir() as $candidate) {
588-
if (!preg_match(self::CLASS_NAME_REGEX, $candidate)) {
589-
continue;
590-
}
591-
$path = $this->directory . '/' . $candidate;
592-
if (!\is_dir($path)) {
584+
foreach (NsDirUtil::getDirContents($this->directory) as $candidate => $is_dir) {
585+
if (!$is_dir || !preg_match(self::CLASS_NAME_REGEX, $candidate)) {
593586
continue;
594587
}
595588
yield $candidate => $this->subdir($candidate);
596589
}
597590
}
598591

599-
/**
600-
* Runs scandir() on this namespace directory.
601-
*
602-
* Throws a runtime exception on failure, instead of returning false.
603-
* This is considered an unhandled exception, because it is assumed that the
604-
* current directory always exists.
605-
*
606-
* @return list<string>
607-
* Items in the directory in alphabetic order.
608-
* This also includes '.' and '..'.
609-
*/
610-
private function scanThisDir(): array {
611-
return NsDirUtil::scanKnownDir($this->directory);
612-
}
613-
614592
}

src/NsDirUtil.php

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,10 @@ public static function assertReadableDirectory(string $dir): void {
7777
* Format: $[$file] = $class
7878
*/
7979
private static function doIterateRecursively(string $dir, string $terminatedNamespace): \Iterator {
80-
foreach (self::scanKnownDir($dir) as $candidate) {
81-
if ('.' === $candidate[0]) {
82-
continue;
83-
}
80+
foreach (self::getDirContents($dir) as $candidate => $is_dir) {
8481
$path = $dir . '/' . $candidate;
85-
if (\str_ends_with($candidate, '.php')) {
86-
if (!is_file($path)) {
82+
if (!$is_dir) {
83+
if (!\str_ends_with($candidate, '.php')) {
8784
continue;
8885
}
8986
$name = substr($candidate, 0, -4);
@@ -94,9 +91,6 @@ private static function doIterateRecursively(string $dir, string $terminatedName
9491
yield $path => $terminatedNamespace . $name;
9592
}
9693
else {
97-
if (!is_dir($path)) {
98-
continue; // @codeCoverageIgnore
99-
}
10094
if (!preg_match(self::CLASS_NAME_REGEX, $candidate)) {
10195
continue;
10296
}
@@ -109,27 +103,25 @@ private static function doIterateRecursively(string $dir, string $terminatedName
109103
}
110104

111105
/**
112-
* Runs scandir() on a known directory.
113-
*
114-
* Throws a runtime exception on failure, instead of returning false.
115-
* This is considered an unhandled exception, because it is assumed that the
116-
* given directory always exists.
106+
* Gets names of files and subdirectories in a directory.
117107
*
118108
* @param string $dir
119-
* Known directory to scan.
109+
* Parent directory to scan.
110+
*
111+
* @return array<string, bool>
112+
* Array where the keys are file or directory names, and the values indicate
113+
* whether the entry is a directory.
120114
*
121-
* @return list<string>
122-
* Items in the directory in alphabetic order.
123-
* This also includes '.' and '..'.
124-
* Calling code already does filtering with regex or other means, so it
125-
* would be redundant to do additional filtering here.
115+
* @internal
126116
*/
127-
public static function scanKnownDir(string $dir): array {
128-
$candidates = @\scandir($dir, \SCANDIR_SORT_ASCENDING);
129-
if ($candidates === false) {
130-
throw new \RuntimeException("Failed to scandir('$dir').");
117+
public static function getDirContents(string $dir): array {
118+
$iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS|\FilesystemIterator::KEY_AS_FILENAME|\FilesystemIterator::CURRENT_AS_SELF);
119+
$contents = [];
120+
foreach ($iterator as $name => $iterator_self) {
121+
$contents[$name] = $iterator->hasChildren();
131122
}
132-
return $candidates;
123+
ksort($contents);
124+
return $contents;
133125
}
134126

135127
}

tests/src/NsDirUtilTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function testIterate(): void {
5858
// Only read permissions, no execute bit.
5959
// The directory will appear as empty.
6060
chmod($dir, $perms & 0444);
61-
$this->assertNull(NsDirUtil::iterate($dir, '')->key());
61+
$this->assertSame($file, NsDirUtil::iterate($dir, '')->key());
6262
$this->assertFalse(@include $file);
6363
}
6464

@@ -85,9 +85,9 @@ public function testAssertReadableDirectory(): void {
8585
$f($dir);
8686
}
8787

88-
public function testScanKnownDir(): void {
89-
$f = NsDirUtil::scanKnownDir(...);
90-
$this->callAndAssertException(\RuntimeException::class, fn () => $f(__DIR__ . '/NonExistingDir'));
88+
public function testGetDirContents(): void {
89+
$f = NsDirUtil::getDirContents(...);
90+
$this->callAndAssertException(\UnexpectedValueException::class, fn () => $f(__DIR__ . '/NonExistingDir'));
9191
}
9292

9393
}

0 commit comments

Comments
 (0)