没有不值得去解决的问题,也没有不值得去学习的技术!

基于 SPL 迭代器 过滤掉目录中不需要的文件实现

运行时报错
1、在一个模板目录中,由于存在一些需要忽略的文件,也被写入至表中,因此,需要过滤掉。参考:在 Laravle 6、TOGoS/PHPGitIgnore 中,用于解析和应用 .gitignore 类规则的实现 2、现阶段的代码实现


    private \RecursiveIteratorIterator $iterator;

    private $themeLocation;

    public function __construct($themeLocation)
    {
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($themeLocation, \FilesystemIterator::SKIP_DOTS)
        );
        $this->iterator = $iterator;
        $this->themeLocation = $themeLocation;
    }


3、导致的结果就是例如:node_modules 开头的文件被写入至数据库中。如图1
导致的结果就是例如:node_modules 开头的文件被写入至数据库中
图1
4、期望通过 The RecursiveFilterIterator class 实现,避免将忽略文件写入至数据库中。这个抽象迭代器为 RecursiveIterator 过滤掉不需要的值。应扩展此类以实现自定义过滤器。 RecursiveFilterIterator::accept() 必须在子类中实现。参考:https://www.php.net/manual/zh/class.recursivefilteriterator.php 。Recursive directory/file listing, filteres “.svn”。 5、新建 ThemeViewIgnoreFinder.php,以获取忽略文件数组。includeDirectories 设置为 true,以包含目录。


<?php

namespace Modules\ThemeStoreDB\Installer;

use TOGoS_GitIgnore_FileFinder;
use TOGoS_GitIgnore_Ruleset;

class ThemeViewIgnoreFinder
{
    const THEMEIGNORE = '.themeignore'; // 主题忽略配置文件

    public $ignoreResults;

    private $themeLocation;

    public function __construct($themeLocation)
    {
        $this->themeLocation = $themeLocation;
        $this->ignoreResults = [];
    }

    /**
     * 添加忽略文件
     * @param $f
     * @param $result
     * @return void
     */
    public function addIgnoreResult($f, $result) {
        $this->ignoreResults[$f] = $result;
    }

    /**
     * 查找忽略文件
     * @return array
     */
    public function findIgnoreFiles() {
        $rulesContent = file_get_contents($this->themeLocation . DIRECTORY_SEPARATOR . self::THEMEIGNORE);
        $finder = new TOGoS_GitIgnore_FileFinder([
            'ruleset' => TOGoS_GitIgnore_Ruleset::loadFromString($rulesContent),
            'invertRulesetResult' => false,
            'defaultResult' => false,
            'includeDirectories' => true,
            'callback' => [$this, 'addIgnoreResult']
        ]);

        $finder->findFiles($this->themeLocation);

        return $this->ignoreResults;
    }

}



6、新建 ThemeViewRecursiveFilterIterator.php,以实现自定义过滤器


<?php

namespace Modules\ThemeStoreDB\Installer;

class ThemeViewRecursiveFilterIterator extends \RecursiveFilterIterator
{
    protected $filters;

    public function __construct(\RecursiveIterator $iterator, $ignoreResults) {

        $this->filters = $ignoreResults;
        parent::__construct($iterator);
    }

    public function accept() {

        $accept = true;

        if (isset($this->filters[$this->current()->getFilename()])) {
            $accept = !$this->filters[$this->current()->getFilename()];
        }

        return $accept;
    }


}



7、编辑 SPL 迭代器 代码实现


    private \RecursiveIteratorIterator $iterator;

    private $themeLocation;

    public function __construct($themeLocation)
    {
        $dirIterator = new \RecursiveDirectoryIterator($themeLocation, \FilesystemIterator::SKIP_DOTS);
        $themeViewIgnoreFinder = new ThemeViewIgnoreFinder($themeLocation);
        $filterIterator = new ThemeViewRecursiveFilterIterator($dirIterator, $themeViewIgnoreFinder->findIgnoreFiles());
        $iterator = new \RecursiveIteratorIterator($filterIterator);

        $this->iterator = $iterator;
        $this->themeLocation = $themeLocation;
    }


8、运行时报错。如图2
运行时报错
图2


PS E:\wwwroot\object> php artisan theme-store:theme:install E:\wwwroot\object\resources\views\theme 12345 blade
安装主题到数据仓库

   Symfony\Component\Debug\Exception\FatalThrowableError  : Too few arguments to function Modules\ThemeStoreDB\Installer\ThemeViewRecursiveFilterIterator::__construct(), 1 passed and exactly 2 expected

  at E:\wwwroot\object\Modules\ThemeStoreDB\Installer\ThemeViewRecursiveFilterIterator.php:9
     5| class ThemeViewRecursiveFilterIterator extends \RecursiveFilterIterator
     6| {
     7|     protected $filters;
     8|
  >  9|     public function __construct(\RecursiveIterator $rit, $ignoreResults) {
    10|
    11|         $this->filters = $ignoreResults;
    12|         parent::__construct($rit);
    13|     }

  Exception trace:

  1   Modules\ThemeStoreDB\Installer\ThemeViewRecursiveFilterIterator::__construct(Object(RecursiveDirectoryIterator))
      [internal]:0

  2   RecursiveFilterIterator::getChildren()
      [internal]:0

  Please use the argument -v to see more details.


9、编辑 ThemeViewRecursiveFilterIterator.php,添加方法 getChildren()


<?php

namespace Modules\ThemeStoreDB\Installer;

class ThemeViewRecursiveFilterIterator extends \RecursiveFilterIterator
{
    protected $filters;

    public function __construct(\RecursiveIterator $iterator, $ignoreResults) {

        $this->filters = $ignoreResults;
        parent::__construct($iterator);
    }

    public function accept() {

        $accept = true;

        if (isset($this->filters[$this->current()->getFilename()])) {
            $accept = !$this->filters[$this->current()->getFilename()];
        }

        return $accept;
    }

    public function getChildren() {
        return new self($this->getInnerIterator()->getChildren(), $this->filters);
    }

}



10、再次运行,运行成功,但 node_modules\ 开头的文件仍被写入至数据库中。不符合预期。打印 $this->filters


array(766) {
  [""]=>
  bool(false)
  [".browserslistrc"]=>
  bool(true)
  [".env"]=>
  bool(true)
  [".env.development"]=>
  bool(true)
  [".env.production"]=>
  bool(true)
  [".themeignore"]=>
  bool(true)
  ["assets"]=>
  bool(false)
  ["assets/css"]=>
  bool(false)
  ["assets/css/app.css"]=>
  bool(true)
  ["assets/images"]=>
  bool(false)
}


11、打印 $this->current()->getPath() 、$this->current()->getFilename()


E:\wwwroot\object\resources\views\theme
.browserslistrc
E:\wwwroot\object\resources\views\theme
.env
E:\wwwroot\object\resources\views\theme
.env.development
E:\wwwroot\object\resources\views\theme
.env.production
E:\wwwroot\object\resources\views\theme
.themeignore
E:\wwwroot\object\resources\views\theme
assets
E:\wwwroot\object\resources\views\theme\assets
css
E:\wwwroot\object\resources\views\theme\assets\css
app.css
E:\wwwroot\object\resources\views\theme\assets
images


12、原因在于判断文件路径是否应被过滤掉的规则不正确。重新实现如下


    /**
     * 添加忽略文件
     * @param $f
     * @param $result
     * @return void
     */
    public function addIgnoreResult($f, $result) {
        $this->ignoreResults[$this->themeLocation . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $f)] = $result;
    }




    public function accept() {
        return !$this->filters[$this->current()->getPath() . DIRECTORY_SEPARATOR . $this->current()->getFilename()];
    }


13、再次运行,运行成功,且 node_modules 开头的文件已未被写入至数据库中。符合预期。如图3
再次运行,运行成功,且 node_modules 开头的文件已未被写入至数据库中。符合预期
图3

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理