public function getFilenames(array $fileOrDirectoryNames, array $filePatterns = [], FinderObserver $observer = null): array
    {
        $finder = clone $this->finder;
        $finder->files();

        $observer = $observer ?: new CallbackFinderObserver(function() {});

        if (count($filePatterns) > 0) {
            $finder->filter(function(SplFileInfo $fileInfo) use ($filePatterns) {
                if ($fileInfo->isDir()) {
                    return true;
                }

                foreach ($filePatterns as $pattern) {
                    if (fnmatch($pattern, $fileInfo->getFilename())) {
                        return true;
                    }
                }
                return false;
            });
        }

        $filenames = [];

        foreach ($fileOrDirectoryNames as $fileOrDirectoryName) {
            $subFinder                   = clone $finder;
            $resolvedFileOrDirectoryName = $fileOrDirectoryName;

            if ($fileOrDirectoryName{0} !== '/' && substr($fileOrDirectoryName, 0, 6) !== 'vfs://') {
                $resolvedFileOrDirectoryName = realpath($fileOrDirectoryName);

                if ($resolvedFileOrDirectoryName === false) {
                    $observer->onEntryNotFound($fileOrDirectoryName);
                    continue;
                }
            }

            if (file_exists($resolvedFileOrDirectoryName) === false) {
                $observer->onEntryNotFound($resolvedFileOrDirectoryName);
                continue;
            }

            $fileInfo = $this->filesystem->openFile($resolvedFileOrDirectoryName);
            if ($fileInfo->isFile()) {
                $filenames[] = $resolvedFileOrDirectoryName;
            } else {
                $subFinder->in($resolvedFileOrDirectoryName);

                /** @var SymfonySplFileInfo $subFileInfo */
                foreach ($subFinder as $subFileInfo) {
                    $filenames[] = $subFileInfo->getPathname();
                }
            }
        }

        return $filenames;
    }