首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >分页辅助类

分页辅助类
EN

Code Review用户
提问于 2021-07-01 10:35:14
回答 1查看 102关注 0票数 3

分页最令人作呕的问题是,您必须编写两个几乎相同的查询。由于各种原因,我不倾向于使用SQL方式(如select count(*) from (original query goes here))。因此,我试图修改原始查询。意识到这个方法并不完全可靠,我是以一种半自动的方式这样做的,它为常规查询提供了自动化的方法,偶尔也会返回到自动设置count查询。

目标是使应用程序代码变得简单,同时显式化。与PDO的fetchAll()完全兼容是必需的。

到目前为止,代码对我来说是完美的,但显然我可能忽略了一些边缘情况。此外,我也不确定方法之间的代码分布情况。

这是代码

代码语言:javascript
复制
class Pagination
{
    protected PDO $pdo;
    protected string $sql;
    protected array $params;
    protected string $countSql;
    protected int $limit = 10;

    public function __construct(PDO $pdo, string $sql, array $params = []) {
        $this->pdo = $pdo;
        $this->sql = $sql;
        $this->params = $params;
    }

    public function setCountQuery(string $sql) {
        $this->countSql = $sql;
        return $this;
    }

    public function setLimit(int $limit) {
        $this->limit = $limit;
        return $this;
    }
    
    public function getPageCount():int {
        return (int)ceil($this->getNumRecords() / $this->limit);
    }
    
    public function getNumRecords() {
        $this->countSql = $this->countSql ?? $this->getAutoCountQuery();
        $stmt = $this->pdo->prepare($this->countSql);
        $stmt->execute($this->params);
        return $stmt->fetchColumn();
    }
    
    public function getPageData(int $page, $mode = null, ...$fetchAllParams) {
        $offset = ($page - 1) * $this->limit;
        $limit = (int)$this->limit;

        $mode = $mode ?? $this->pdo->getAttribute(PDO::ATTR_DEFAULT_FETCH_MODE);
    
        $sql = "$this->sql LIMIT $offset, $limit";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($this->params);
        return $stmt->fetchAll($mode, ...$fetchAllParams);
    }

    public function getAutoCountQuery() {
        $pat = '~^(select)(.*)(\s+from\s+)~i';
        return preg_replace($pat, '$1 count(*)$3', $this->sql);
    }
}

下面是一个简单的测试片段,假设您有一个工作的PDO实例

代码语言:javascript
复制
$pdo->query("create temporary table test(i int)");
$pdo->query("insert into test (i) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)");

$pagination = new Pagination($pdo, "select * from test");
$pagination->setLimit(5);
#$pagination->setCountQuery("select count(*) from test");
$pageCount = $pagination->getPageCount();
$data = $pagination->getPageData(1);
$data2 = $pagination->getPageData(2, PDO::FETCH_COLUMN);
$data3 = $pagination->getPageData(3, PDO::FETCH_CLASS, 'stdClass');
var_dump($pageCount, json_encode($data), json_encode($data2), json_encode($data3));
EN

回答 1

Code Review用户

发布于 2021-07-05 14:41:22

使用类的人可能并不知道每次使用getPageCount()方法时都会执行SQL查询。理想情况下,应该只执行一次。这可以通过这样的代码来实现:

代码语言:javascript
复制
class Pagination
{
    protected int $numRecords = -1;

    public function getNumRecords() {
        if ($this->numRecords < 0) {
            $this->countSql = $this->countSql ?? $this->getAutoCountQuery();
            $stmt = $this->pdo->prepare($this->countSql);
            $stmt->execute($this->params);
            $this->numRecords = $stmt->fetchColumn();
        }
        return $this->numRecords;
    }  

}

我忽略了与本例无关的所有属性和方法。

问:如何将PHP参数绑定到查询?

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/263660

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档