PHP Manual
/
データ処理

PHP の Paginator と結果のページネーション

22. 08. 2019

捨てるデータが多いときは、複数のページに分割するのが礼儀です。本稿では、ページ番号の受け渡しや結果の一覧表示の実用化には触れず、大量のページの閲覧をできるだけ使いやすくするための理論的な値の抽出と最適なコードブックの算出についてのみ述べる。

結果はいくつになるのか

そもそも、どれだけの実績があるのかを知る必要がある。データベースからのデータであれば、次のようなSQL文で非常に効率的にカウントすることができる。

SELECT COUNT(*) FROM tabulka

データベースがヘルパーファイルに統計情報を保持しているため、データには全く触れないので、計算は非常に高速に行われます。

もしデータがどこかから来たものであれば(例えば配列で持っている)、count()関数で数えることができる。

$cisla = [3, 1, 4, 1, 5, 9, 2];
echo 'このフィールドには' . count($cisla) . 'の数値が表示されます。';

検索結果の表示件数制限

また、結果数の制限も問題です。データがデータベースにある場合は、SQL文の中にLIMITパラメータを入れるだけです。

SELECT * FROM tabulka WHERE (cokoli) LIMIT 10

このコマンドは常に最大10件の結果を取得します。また、データベースがデータファイル全体を参照する必要がないため、クエリーが高速化されます。

別のソースからのデータ (これも配列) がある場合、ヘルパー変数 $iterator を使用して PHP レベルで結果を制限することもできます。

$pole = [...];
$iterator = 0;
$limit = 10;
foreach ($pole as $prvek) {
// ここにデータがダンプされる
$iterator++;
if ($iterator >= $limit) {
break; // 10回実行したらサイクルを停止する
}
}

最初のX個の結果をスキップする

最初のページにいるときは、とても簡単で、LIMITを使って結果の数を制限すればいいだけです。でも、3ページ目ならどうでしょう?そうすると、最初の X の結果をスキップしなければなりません。

SQLでは、これまたエレガントな記法があります。

SELECT * FROM tabulka WHERE (cokoli) LIMIT 10 OFFSET 20

最初の20件をスキップして、次の出力を10件に制限しているので、区間<21 - 30>を出力しています。

純粋なPHPでは、これは2つの方法で処理されます。

配列のインデックスがわかっていれば、ある地点から読み始めることができます(非常に高速です)。

$pole = [...];
$start = 20;
$limit = 10;
for ($i = $start; ($i <= $start + $limit && isset($pole[$i])); $i++) {
// ここにデータがダンプされる
}

しかし、未知のフィールドに対しては、再度イテレータを使用し、項目をスキップしなければならない。

$pole = [...];
$iterator = 0;
$start = 20;
$limit = 10;
foreach ($pole as $prvek) {
if ($iterator < $start) {
$iterator++;
continue;
}
// どういうわけか、ここにデータがダンプされている
$iterator++;
if ($iterator >= $start + $limit) break;
}

最適なページャ/ステッパの表示

総項目数、ページ内の項目数、現在のページ番号が分かっているとする。今度は、検索結果を含む全ページを高速にブラウズできるバーをレンダリングしたい。しかし、ページ数が多い(数千のオーダー)ので、一度に全部をリストアップすることはできず、ページ間の範囲を最もよく表す代表的なものを賢く選ぶ必要があるのです。

このように見えるかもしれません。

1 | 15 | 30 | 36 | 45 | 60 | 72

アサインメントです。

72ページ中36ページ目なのですが、ページ番号を最適に配置するにはどうしたらよいでしょうか? まあ、順を追って。

Tip:** Paginatorの左側は等差数列(同じステップ数で直線的に移動できる)、右側は幾何級数列で計算すると、大きなステップが簡単にできることが、実際の観察でわかりました。そのため、特定のページにたどり着きたい場合は、まず不要なものを大量に飛ばし、左に戻って絞り込んでいくのです。

算術数列の理論(同じ数を足し続ける)。

$d = 10; // ステップサイズ
$a[1] = 1; // 最初の要素
$a[2] = $a[1] + $d; // 2番目の要素
$a[3] = $a[1] + 2 * $d;
$a[3] = $a[2] + $d;
$a[$n] = $a[1] + ($n - 1) * $d; // n番目の要素
function getAritmeticItem(int $start, int $step, int $n): int
{
return $start + ($n - 1) * $step;
}

幾何学数列理論(常に同じ数を掛ける)。

$q = 10; // ステップサイズ
$a[1] = 1; // 最初の要素
$a[2] = $a[1] * $q; // 2番目の要素
$a[3] = $a[1] * $q * $q;
$a[3] = $a[1] * pow($q, 2);
$a[3] = $a[2] * $q;
$a[$n] = $a[1] * pow($q, $n - 1); // n番目の要素
function getGeometricItem(int $start, int $step, int $q): int
{
return $start * pow($q, $step - 1);
}

$start = 1;
$current = 36;
$end = 72;

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
Status:
All systems normal.
2024