Почему базовый класс ловит исключение?
А почему catch (Exception $e) ловит все остальные исключения, вы не задумывались? Ведь он не знает все особенности всех своих производных классов.

Блок catch обрабатывает исключение подходящего типа в порядке объявления этих блоков. Объект класса FileNotFoundException является также и объектом класса FilesystemException (как и объектом класса Exception).

Хотите обрабатывать отдельно FileNotFoundException, вставьте соответствующий catch-блок до catch (FilesystemException $e).
Это очень плохой подход.
Все делается ради красивости, а не для реальной пользы.
FileWriteException может случиться примерно по 100500 разных причин.
НИ ОДНА ИЗ НИХ не будет сообщена несчастному разработчику, который будет пытаться понять, ПОЧЕМУ не получилось файл записать.  Ему, как в том анекдоте, будут говорить "слушайте свою песню Валенки!", вместо реального сообщения об ошибке.

Кидать красивости можно на уровне файлового враппера, но при этом обязательно сохранять исходное сообщение об ошибке!

public function write($filename, $data) {
    try {
        file_put_contents($filename, $data);
    } catch (Throwable $e) {
        $e = new FileWriteException($e->getMessage());
        $e->setName($filename);
        throw $e;
    }
}