PHP Profi

Новая мажорная версия Flysystem Перевод

alt

Для тех, кто пропустил: 24 ноября вышла новая мажорная версия Flysystem. Новая версия позволяет порвать с прошлым ради будущего, что я и сделал.

Для создания второй версии Flysystem я начал с чистого листа. Многие основные элементы дизайна библиотеки были почищены и улучшены. API уменьшен, сохраняя при этом свой прежний функционал. Обработка ошибок теперь основана только на исключениях, а листинг директорий теперь используют генераторами. Несмотря на то, что изменений много, эта версия Flysystem верна своим корням. Давайте погрузимся в детали!

Исключения для сбоев

В версии V1 ошибки моделировались максимально схоже с собственными функциями файловой системы PHP. Такие функции используют false в качестве индикатора неудачной операции. И, хотя такой подход работал, он вызывал сложности в Flysystem и коде, который использовал его. Иногда это также приводило к потере информации при работе с ошибками. Для непредвиденных ошибок всё-таки использовались исключения. Данная конструкция образовывала два разных пути борьбы с ошибками, что приводило к подобным конструкциям:

try {  
  $success = $filesystem->write($path, $contents);

  if ($success === false) {
    // handle error
  }
} catch (Throwable $exception) {
  // handle an exception
}

Хоть это и не является огромной проблемой, но когда вы используете Flysystem, подобный код дублируется на каждом этапе интеграции. Внутренние части библиотеки страдали от такого же рода дублирования, что приводило к лишней запутанности.

В версии V2 все ошибки представлены в качестве исключений. Каждая операция с файловой системой имеет соответствующий класс-исключение. Каждый такой класс объясняет, что было исходной операцией и что пошло не так. Если основной SDK или клиентская библиотека генерируют исключение, Flysystem обязательно обернет его в определенное исключение Flysystem, сохраняя соответствующий стек-трейс. Это позволяет обрабатывать исключения единообразно, сохраняя при этом всю информацию, необходимую для отладки любых проблем.

try {  
   $filesystem->write($path, $contents);
} catch (UnableToWriteFile $exception) {
 // handle the error
}

Детерминированные операции над файловой системой

В версии V1 было два способа записи файла. Функции write и writeStream позволяли записывать новые файлы. Для обновления файлов использовались функции update и updateStream. Эти методы выполняли проверку существования файла, чтобы предотвратить перезапись файлов или попытку обновления несуществующего файла. Хотя в то время это казалось полезным, это стало большим разочарованием для меня, так как это привело к большому количеству условных выражений в использующемся коде. Это также вызывает ненужные проверки, часто приводящие к дорогостоящим вызовам по сети.

if ($filesystem->has($file)) {  
  $filesystem->update($file, $contents);
} else {
  $filesystem->write($file, $contents);
}

Если бы в приведенном выше примере использовался AWS S3, то этот блок кода всегда вызывал бы 3 HTTP-запроса.

В V2 все операции записи и удаления являются детерминированными. Для записи это означает, что файл с предоставленным содержимым всегда будет записан. Для удаления это означает, что операция удаления выполнена успешно, даже если файл не существовал. Результат всегда таков: "теперь файла больше нет". Это устраняет множество шансов возникновения "состояний гонки", вызванных самой библиотекой, и упрощает использование кода. Такое поведение устранило необходимость использовать функцию update, поэтому update и updateStream теперь удалены.

$filesystem->write($path, $contents);

// если вам действительно необходимо проверить существование файла 
$fileExists = $filesystem->fileExists($pathToFile);

По сравнению с V1, для записи или обновления файла на S3 потребуется всего 1 HTTP-вызов.

Листинг содержимого через генераторы

В версии V1 листинг директорий возвращал массив ассоциативных массивов с относительно хорошо стандартизированными свойствами/ключами. Данное решение было очень практичным, но имело свои ограничения. Во-первых, использующийся код должен был знать, какие ключи доступны в массивах, и в IDE не было никаких хинтов. Кроме того, весь список был полностью получен (fetch) перед его возвратом. Для больших списков директорий это могло приводить (и часто приводило) к тому, что у процессов заканчивалась память.

В версии V2 листинг директорий используется генераторами. Это позволяет гораздо более эффективно использовать память для листинга содержимого директории. Кроме того, Filesystem возвращает объект DirectoryListing, который добавляет некоторые удобные методы, такие как filter и map.

Давайте сравним кейс, когда мы фильтруем и сопоставляем списки директорий. Вот как это работало в V1:

$listing = $filesystem->listContents('path/to/dir');

$files = array_filter(
  $listing,
  fn ($i) => $i['type'] === 'file',
);

$paths = array_map(
  fn ($i) => $i['path']
  $files,
);

И вот как это выглядит в V2:

$paths = $filesystem->listContents('path/to/dir')
  ->filter(fn (StorageAttributes $i) => $i->isFile())
  ->map(fn (StorageAttributes $i) => $i->path())
  ->toArray();

Попробуйте V2!

Я считаю, что библиотека Flysystem готова к предстоящей необходимости в абстрагировании файловой системы, и надеюсь, что вы будете рады начать её использовать. Для получения дополнительной информации ознакомьтесь с документацией.

2023-02-03 оригинал

Последние посты

Комментарии

авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий