首页 > 解决方案 > 为什么这个`while`循环在更改数据时不处理所有记录?

问题描述

while在 WordPress 脚本中有一个 PHP 循环,当它修改数据时,它似乎只处理了它应该处理的一半记录,我很难理解为什么会发生这种情况。

我正在编写一个 WP-CLI 脚本,它将在所有尚未拥有它的评论上设置一个带有键reviewed和值的元数据。1我的脚本如下所示:

class Mark_Comments_Reviewed {

    public function __invoke() {

        $limit  = 100;
        $offset = 0;

        while ( $comment_ids = $this->get_unreviewed_comments( $limit, $offset ) ) {

            array_walk(
                $comment_ids,
                function ( $comment_id ) {
                    $comment_id = (int) $comment_id;
                    $this->process_comment( $comment_id );
                }
            );

            $offset += $limit;
        }
    }

    protected function get_unreviewed_comments( int $limit, int $offset ): array {

        global $wpdb;

        return $wpdb->get_col(
            $wpdb->prepare(
                "SELECT DISTINCT comments.comment_ID
                        FROM wp_comments AS comments
                        AND comments.comment_ID NOT IN (
                            SELECT meta.comment_id
                            FROM wp_commentmeta AS meta
                            WHERE meta.meta_key = 'reviewed'
                        )
                        LIMIT %d
                        OFFSET %d",
                $limit,
                $offset
            )
        );
    }

    protected function process_comment( int $comment_id ): bool {
        return ! ! update_comment_meta( $comment_id, 'reviewed', (int) true );
    }

}

(该wp_commentmeta表有字段meta_idmeta_key,meta_value andcomment_id , and the last field relates to the ID of a comment record in thewp_comments`表。)

我有 810 条没有元数据的评论。当我像这样运行脚本时,它完成了 410 的处理。当我用 替换该$this->process_comment( $comment_id );行时return true,脚本“处理”所有 810。

通话恢复后process_comment,我必须运行脚本四次才能处理所有 810 条记录。

显然,评论元数据的更新导致循环在它应该完成之前完成。我错过了一些明显的东西吗?


编辑

我发现脚本只处理每隔一批的 100 条记录。

标签: phpsqlwordpresswhile-loop

解决方案


啊啊啊!这是偏移量!当我删除它时,脚本会按预期处理所有记录。

循环的第一次迭代处理了前 100 条记录,将它们从没有元值的记录集中删除。这留下了 710。但是下一次迭代从偏移 100 开始,这意味着这 710 中的前 100 个没有被处理。我不需要偏移量——我只需要每次选择第一批剩余的记录。

更正的脚本是

class Mark_Comments_Reviewed {

    public function __invoke() {

        $limit  = 100;

        while ( $comment_ids = $this->get_unreviewed_comments( $limit ) ) {
            array_walk(
                $comment_ids,
                function ( $comment_id ) {
                    $comment_id = (int) $comment_id;
                    $this->process_comment( $comment_id );
                }
            );
        }
    }

    protected function get_unreviewed_comments( int $limit ): array {

        global $wpdb;

        return $wpdb->get_col(
            $wpdb->prepare(
                "SELECT DISTINCT comments.comment_ID
                    FROM wp_comments AS comments
                    AND comments.comment_ID NOT IN (
                        SELECT meta.comment_id
                        FROM wp_commentmeta AS meta
                        WHERE meta.meta_key = 'reviewed'
                    )
                    LIMIT %d"
                $limit
            )
        );
    }

    protected function process_comment( int $comment_id ): bool {
        return ! ! update_comment_meta( $comment_id, 'reviewed', (int) true );
    }

}

推荐阅读