筛选器
筛选器用于控制快照中包含哪些数据。你可以排除缓存表、忽略易变的时间戳列,或跳过临时行。筛选器会在捕获快照时应用,并影响所有后续操作(差异比较、合并和应用)。
PHP
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Snapshot\Snapshotter;
$snapshotter = new Snapshotter($connection);
$snapshot = $snapshotter->capture('baseline', filters: [
TableFilter::exclude(['sessions', 'cache_*']),
ColumnFilter::ignore(['updated_at', 'modified_date']),
]);
TableFilter
控制快照中包含哪些表。支持通过 PHP 的 fnmatch() 使用 glob 模式。
排除表
PHP
use Merql\Filter\TableFilter;
$filter = TableFilter::exclude(['sessions', 'cache_*', 'wp_*_log']);
任何与排除模式匹配的表都会从快照中省略。* 通配符可匹配任意字符序列。
包含表
PHP
$filter = TableFilter::include(['posts', 'comments', 'users']);
只捕获与包含模式匹配的表。其余表都会被排除。
工作原理
筛选器的 apply() 方法接收表名列表,并返回筛选后的子集:
PHP
$allTables = ['posts', 'comments', 'sessions', 'cache_pages', 'users'];
$filter = TableFilter::exclude(['sessions', 'cache_*']);
$filtered = $filter->apply($allTables);
// ['posts', 'comments', 'users']
$filter = TableFilter::include(['posts', 'users']);
$filtered = $filter->apply($allTables);
// ['posts', 'users']
如果同时存在包含和排除模式(通过单独的筛选器实例提供),则先评估排除模式。表必须不匹配任何排除模式,并且至少匹配一个包含模式,才会被保留。
ColumnFilter
在捕获期间从行数据中移除指定列。适用于每次写入都会变化、可能导致错误差异的易变列。
PHP
use Merql\Filter\ColumnFilter;
$filter = ColumnFilter::ignore(['updated_at', 'modified_date', 'last_login']);
常见用例
updated_at/modified_at时间戳,每次保存都会变化。revision自动递增计数器。session_token或其他临时字段。
工作原理
行键计算完成后,筛选器会从每一行中移除指定列:
PHP
$filter = ColumnFilter::ignore(['updated_at']);
$row = ['id' => 1, 'title' => 'Hello', 'updated_at' => '2026-01-15 10:30:00'];
$filtered = $filter->applyToRow($row);
// ['id' => 1, 'title' => 'Hello']
行键(标识)根据未筛选的行计算。这意味着列筛选器不会影响标识列。只有用于指纹计算和差异比较的数据会经过筛选。
RowFilter
使用谓词闭包筛选单行。闭包接收表名和完整行数据,并返回 true 以包含该行,或返回 false 以排除该行。
PHP
use Merql\Filter\RowFilter;
// Exclude draft posts.
$filter = RowFilter::create(function (string $table, array $row): bool {
if ($table === 'posts' && ($row['status'] ?? '') === 'draft') {
return false;
}
return true;
});
// Exclude rows with NULL email.
$filter = RowFilter::create(function (string $table, array $row): bool {
if ($table === 'users') {
return $row['email'] !== null;
}
return true;
});
工作原理
捕获期间会为每一行调用 shouldInclude() 方法:
PHP
$include = $filter->shouldInclude('posts', ['id' => 1, 'status' => 'draft']);
// false
被排除的行不会计算指纹,不会存储在快照中,也不会出现在差异或合并结果中。
组合筛选器
向 capture() 传入多个筛选器。每种筛选器类型最多使用一个:
PHP
$snapshot = $snapshotter->capture('baseline', filters: [
TableFilter::exclude(['cache_*']),
ColumnFilter::ignore(['updated_at']),
RowFilter::create(fn($table, $row) => ($row['active'] ?? '1') === '1'),
]);
处理顺序:
- 首先运行 TableFilter,确定要捕获哪些表。
- 对每张表,从数据库读取行。
- 对每一行运行 RowFilter,排除不匹配的行。
- 根据未筛选的行计算 行键(身份列保持完整)。
- ColumnFilter 从行数据中移除忽略的列。
- 根据筛选后的行数据计算 指纹。
此顺序确保始终可以使用标识列计算键,即使这些列之后会被列筛选器移除。
筛选器与一致性
合并时,三个快照(base、ours、theirs)应使用相同的筛选器。如果使用不同的筛选器,某些行或列可能会看起来像是新增或删除,实际上只是筛选方式不同。
PHP
// Use the same filter set for all snapshots.
$filters = [
TableFilter::exclude(['sessions']),
ColumnFilter::ignore(['updated_at']),
];
$base = $snapshotter->capture('base', filters: $filters);
$ours = $snapshotter->capture('ours', filters: $filters);
$theirs = $snapshotter->capture('theirs', filters: $filters);