Быстрое и простое решение
Вы можете упростить свою жизнь и использовать DirectoryIterator
для просмотра каталога.
echo '<select name="vids" size="4">';
foreach( new DirectoryIterator('/path/to/videos') as $file) {
if( $file->isFile() === TRUE && $file->getBasename() !== '.DS_Store') {
printf("<option>%s</option>\n", htmlentities($file->getBasename()));
}
}
echo '</select>';
Улучшение: Отсоединение фильтрации каталогов от здания SelectBox
Если вы хотите отделить логику фильтрации от цикла foreach
, вы можете создать подкласс FilterIterator
для капсулыэта логика в это accept()
метод.DirectoryIterator
должен быть включен в FilterIterator
тогда.Главное - это возможность многократного использования:
class MyFilter extends FilterIterator
{
public function accept()
{
return $this->current()->isFile() === TRUE &&
$this->current()->getBasename() !== '.DS_Store';
}
}
$iterator = new MyFilter(new DirectoryIterator('/path/to/videos'));
Когда вы используете foreach
на отфильтрованном итераторе, он автоматически запускает accept()
.Если accept()
возвращает FALSE
, текущий элемент будет отфильтрован в итерации.
Вы создаете SelectBox следующим образом:
echo '<select name="vids" size="4">';
foreach( $iterator as $file) {
printf("<option>%s</option>\n", htmlentities($file->getBasename()));
}
echo '</select>';
Альтернатива созданию подкласса FilterIterator
Если вам лень писатьотделите FilterIterator
или подумайте, что это просто не стоит того или иного случая, или где-то уже есть валидаторы, и вы не хотите дублировать их код, но все же хотите отделить создание Filtering и SelectBox, вы также можете использовать этот пользовательский FilterChainIterator
и добавьте к нему обратные вызовы:
$iterator = new FilterChainIterator(new DirectoryIterator('/path/to/videos'));
$iterator->addCallback(function($file) {
return $file->isFile() === TRUE &&
$file->getBasename() !== '.DS_Store';});
Создание SelectBox будет таким же, как показано выше.
Улучшение: повторное использование создания SelectBox
Кроме того, если вы хотите сделать создание SelectBox повторно используемым, почему бы не создать помощник для него.Ниже приведен очень простой пример, который использует DOM для создания фактического HTML.Вы передаете любой итератор, и он создает HTML для вас, когда вы вызываете его метод render()
или используете его в строковом контексте:
class SelectBox
{
protected $iterator;
public function __construct(Iterator $iterator)
{
$this->iterator = $iterator;
}
public function render()
{
$dom = new DOMDocument;
$dom->formatOutput = TRUE;
$dom->loadXml('<select name="vids"/>');
$dom->documentElement->appendChild(new DOMElement('option', 'Pick One'));
foreach($this->iterator as $option) {
$dom->documentElement->appendChild(
new DOMElement('option', $option));
}
return $dom->saveXml($dom->documentElement);
}
public function __toString()
{
return $this->render();
}
}
И затем печать SelectBox из итератора так же проста, как
echo new SelectBox(new MyFilter(new DirectoryIterator('/path/to/videos')));
Это довольно гибко, учитывая, что для всего есть Итераторы.Например,
echo new SelectBox(new ArrayIterator(array('foo', 'bar', 'baz')));
даст аккуратно отформатированный
<select>
<option>Pick One</option>
<option>foo</option>
<option>bar</option>
<option>baz</option>
</select>