通过 SPL 迭代器递归扫描目录的标准方法是:
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $file) {
print $file->getPathname() . PHP_EOL;
}
我想要一组可组合的过滤器来应用于我的递归文件搜索。我正在使用 RecursiveDirectoryIterator 来扫描目录结构。
我想对我的目录结构应用多个过滤器。
我的设置代码:
$filters = new FilterRuleset(
new RecursiveDirectoryIterator($path)
);
$filters->addFilter(new FilterLapsedDirs);
$filters->addFilter(new IncludeExtension('wav'));
$files = new RecursiveIteratorIterator(
$filters, RecursiveIteratorIterator::CHILD_FIRST
);
我想我可以通过使用规则集来应用 N 个过滤器:
class FilterRuleset extends RecursiveFilterIterator {
private $filters = array();
public function addFilter($filter) {
$this->filters[] = $filter;
}
public function accept() {
$file = $this->current();
foreach ($this->filters as $filter) {
if (!$filter->accept($file)) {
return false;
}
}
return true;
}
}
我设置的过滤没有按预期工作。当我检查 FilterRuleset 中的过滤器时,它们会在第一次调用时填充,然后在后续调用中变为空白。就好像 RecursiveIteratorIterator 在内部重新实例化我的 FilterRuleset。
public function accept() {
print_r($this->filters);
$file = $this->current();
foreach ($this->filters as $filter) {
if (!$filter->accept($file)) {
return false;
}
}
return true;
}
输出:
Array
(
[0] => FilterLapsedDirs Object
(
)
[1] => IncludeExtension Object
(
[ext:private] => wav
)
)
Array
(
)
Array
(
)
Array
(
)
Array
(
)
Array
(
)
Array
(
)
我使用的是 PHP 5.1.6,但在 5.4.14 上测试过,没有区别。有什么想法吗?
最佳答案
When I check the filters in FilterRuleset they are populated on the first call, then blank on subsequent calls. Its as if internally RecursiveIteratorIterator is re-instantiating my FilterRuleset.
是的,确实如此。每次进入子目录时,数组都是空的,因为根据递归迭代器规则,递归过滤器迭代器需要提供子迭代器。
所以你在这里有两个选择:
getChildren() 返回一个已配置的 FilterRuleset 递归过滤器迭代器对象和过滤器集。我从第二个开始,因为它很快就完成了,而且是正常的方法。
您通过将 getChildren() 父方法添加到您的类来覆盖它。然后你获取父级的结果(这是新的 FilterRuleset 用于子级并设置私有(private)成员。这在 PHP 中是可能的(如果你想知道他的作品是因为它是私有(private)成员)因为它在类层次结构的同一级别。然后您只需返回它并完成:
class FilterRuleset extends RecursiveFilterIterator
{
private $filters = array();
...
public function getChildren() {
$children = parent::getChildren();
$children->filters = $this->filters;
return $children;
}
}
另一个(第一个)变体是您基本上将其“降级”为“扁平”过滤器,即标准的 FilterIterator。因此,您首先使用 RecursiveIteratorIterator 进行递归迭代,然后将其包装到过滤器迭代器中。由于树已被较早的迭代器遍历,因此不再需要所有这些递归的东西。
所以首先把它变成一个FilterIterator:
class FilterRuleset extends FilterIterator
{
...
}
唯一的变化是您使用该类扩展的内容。你以稍微不同的顺序实例化:
$path = __DIR__;
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
$filtered = new FilterRuleset($files);
$filtered->addFilter(Accept::byCallback(function () {
return true;
}));
foreach ($filtered as $file) {
echo $file->getPathname(), PHP_EOL;
}
我希望这些例子很清楚。如果您尝试这些并遇到问题(或者即使没有),欢迎随时提供反馈。
啊,在我忘记它之前:这是我在上面的示例中用来创建过滤器的模拟:
class Accept
{
private $callback;
public function __construct($callback) {
$this->callback = $callback;
}
public function accept($subject) {
return call_user_func($this->callback, $subject);
}
public static function byCallback($callback) {
return new self($callback);
}
}
关于php - RecursiveFilterIterator 在 RecursiveIteratorIterator 中重新实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16712253/
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案
我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_
我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案
我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。
我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认
如果我有以下一段Ruby代码:classBlahdefself.bleh@blih="Hello"@@bloh="World"endend@blih和@@bloh到底是什么?@blih是Blah类中的一个实例变量,@@bloh是Blah类中的一个类变量,对吗?这是否意味着@@bloh是Blah的类Class中的一个变量? 最佳答案 人们似乎忽略了该方法是类方法。@blih将是常量Bleh的类Class实例的实例变量。因此:irb(main):001:0>classBlehirb(main):002:1>defself.blehirb