分页最令人作呕的问题是,您必须编写两个几乎相同的查询。由于各种原因,我不倾向于使用SQL方式(如select count(*) from (original query goes here))。因此,我试图修改原始查询。意识到这个方法并不完全可靠,我是以一种半自动的方式这样做的,它为常规查询提供了自动化的方法,偶尔也会返回到自动设置count查询。
目标是使应用程序代码变得简单,同时显式化。与PDO的fetchAll()完全兼容是必需的。
到目前为止,代码对我来说是完美的,但显然我可能忽略了一些边缘情况。此外,我也不确定方法之间的代码分布情况。
这是代码
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实例
$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));发布于 2021-07-05 14:41:22
使用类的人可能并不知道每次使用getPageCount()方法时都会执行SQL查询。理想情况下,应该只执行一次。这可以通过这样的代码来实现:
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参数绑定到查询?
https://codereview.stackexchange.com/questions/263660
复制相似问题