8000 Use a lazyintertor to close files descriptors when no longer used · symfony/symfony@cb94f87 · GitHub
[go: up one dir, main page]

Skip to content

Commit cb94f87

Browse files
committed
Use a lazyintertor to close files descriptors when no longer used
1 parent 945c7c5 commit cb94f87

File tree

3 files changed

+190
-1
lines changed

3 files changed

+190
-1
lines changed

src/Symfony/Component/Finder/Finder.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
2121
use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
2222
use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
23+
use Symfony\Component\Finder\Iterator\LazyIterator;
2324
use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
2425
use Symfony\Component\Finder\Iterator\SortableIterator;
2526

@@ -635,7 +636,9 @@ public function getIterator()
635636

636637
$iterator = new \AppendIterator();
637638
foreach ($this->dirs as $dir) {
638-
$iterator->append($this->searchInDirectory($dir));
639+
$iterator->append(new LazyIterator(function () use ($dir) {
640+
return $this->searchInDirectory($dir);
641+
}));
639642
}
640643

641644
foreach ($this->iterators as $it) {
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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\Iterator;
13+
14+
/**
15+
* @author Jérémy Derussé <jeremy@derusse.com>
16+
*/
17+
class LazyIterator implements \Iterator
18+
{
19+
/** @var callable */
20+
private $iteratorFactory;
21+
/** @var \Iterator */
22+
private $iterator;
23+
private $initialize = false;
24+
25+
public function __construct(callable $iteratorFactory)
26+
{
27+
$this->iteratorFactory = $iteratorFactory;
28+
}
29+
30+
public function current()
31+
{
32+
if (!$this->initialize) {
33+
$this->iterator = ($this->iteratorFactory)();
34+
$this->initialize = true;
35+
} elseif (null === $this->iterator) {
36+
return false;
37+
}
38+
39+
return $this->iterator->current();
40+
}
41+
42+
public function next()
43+
{
44+
if (!$this->initialize) {
45+
$this->iterator = ($this->iteratorFactory)();
46+
$this->initialize = true;
47+
} elseif (null === $this->iterator) {
48+
return;
49+
}
50+
51+
$this->iterator->next();
52+
}
53+
54+
public function key()
55+
{
56+
if (!$this->initialize) {
57+
$this->iterator = ($this->iteratorFactory)();
58+
$this->initialize = true;
59+
} elseif (null === $this->iterator) {
60+
return null;
61+
}
62+
63+
return $this->iterator->key();
64+
}
65+
66+
public function valid()
67+
{
68+
if (!$this->initialize) {
69+
$this->iterator = ($this->iteratorFactory)();
70+
$this->initialize = true;
71+
} elseif (null === $this->iterator) {
72+
return false;
73+
}
74+
75+
if ($this->iterator->valid()) {
76+
return true;
77+
}
78+
79+
$this->iterator = null;
80+
81+
return false;
82+
}
83+
84+
public function rewind()
85+
{
86+
if (null === $this->iterator) {
87+
$this->iterator = ($this->iteratorFactory)();
88+
$this->initialize = true;
89+
}
90+
91+
$this->iterator->rewind();
92+
}
93+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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\Tests\Iterator;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Finder\Iterator\LazyIterator;
16+
17+
class LazyIteratorTest extends TestCase
18+
{
19+
public function testLazy()
20+
{
21+
new LazyIterator(function () {
22+
$this->markTestFailed('lazyIterator should not be called');
23+
});
24+
25+
$this->expectNotToPerformAssertions();
26+
}
27+
28+
public function testDelegate()
29+
{
30+
$iterator = new LazyIterator(function () {
31+
return new Iterator(['foo', 'bar']);
32+
});
33+
34+
$this->assertCount(2, $iterator);
35+
}
36+
37+
public function testInnerDestructedAtTheEnd()
38+
{
39+
$count = 0;
40+
$iterator = new LazyIterator(function () use (&$count) {
41+
++$count;
42+
43+
return new Iterator(['foo', 'bar']);
44+
});
45+
46+
foreach ($iterator as $x) {
47+
}
48+
$this->assertSame(1, $count);
49+
foreach ($iterator as $x) {
50+
}
51+
$this->assertSame(2, $count);
52+
}
53+
54+
public function testRewindLogic()
55+
{
56+
$count = 0;
57+
$iterator = new LazyIterator(function () use (&$count) {
58+
++$count;
59+
60+
return new Iterator(['foo']);
61+
});
62+
$this->assertSame(0, $iterator->key());
63+
$this->assertInstanceOf(\SplFileInfo::class, $iterator->current());
64+
$this->assertTrue($iterator->valid());
65+
66+
$iterator->next();
67+
68+
$this->assertNull($iterator->key());
69+
$this->assertFalse($iterator->current());
70+
$this->assertFalse($iterator->valid());
71+
72+
// after calling valid, the inner iterator should be set to null.
73+
// Let's check the logic is kept
74+
75+
$this->assertNull($iterator->key());
76+
$this->assertFalse($iterator->current());
77+
$this->assertFalse($iterator->valid());
78+
$iterator->next();
79+
$this->assertNull($iterator->key());
80+
$this->assertFalse($iterator->current());
81+
$this->assertFalse($iterator->valid());
82+
83+
$this->assertSame(1, $count);
84+
85+
// now let's check reset works
86+
$iterator->rewind();
87+
$this->assertSame(2, $count);
88+
89+
$this->assertSame(0, $iterator->key());
90+
$this->assertInstanceOf(\SplFileInfo::class, $iterator->current());
91+
$this->assertTrue($iterator->valid());
92+
}
93+
}

0 commit comments

Comments
 (0)
0