ページング…?
PHPでのページング処理のサンプル。「とりあえず9JP」で、紹介されていたPHPのページング処理を見たら、対象のログファイルを全て読み込んで、そこから必要なデータを出力していたので、軽いファイルの時はまだしも、ちょっとファイルサイズが大きくなったら厳しいと思ったので、片手間に改良してみました。
改良版
PHPでのページング処理のサンプル。で作られたソースを極力変えずに、必要な部分のみ改修してあります。ちょっとエラーもあったので、合わせて修正してあります。
ソース
class TekitouPager {
private $dataArr = array();
private $pageNum = null;
private $maxPageNum = null;
function __construct($dataFile, $maxRecodeNum,$pageNum = '') {
$start = $pageNum * $maxRecodeNum;
$end = $start + $maxRecodeNum;
$file = new SplFileObject($dataFile);
for($i=$start;$i<$end;$i++){
$file->seek($i);
$this->dataArr[] = $file->current();
}
//ページ数を計算
$count = 0;
foreach ($file as $line) {
$count++;
}
$this->maxPageNum = ceil($count / $maxRecodeNum);
$this->pageNum = intval($pageNum);
}
function getPageData() {
//指定されたページの配列を返す
return $this->dataArr;
}
function getNaviLink() {
$naviLink = '';
for ($i = 0; $i < $this->maxPageNum ; $i++) {
//現在のページと一致する場合、太字等の強調
if ($i != $this->pageNum) {
$naviLink .= sprintf('<a href="%s?page=%d">%d</a> ', $_SERVER['SCRIPT_NAME'], $i, $i);
}
else {
$naviLink .= sprintf('<b><a href="%s?page=%d">%d</a></b> ', $_SERVER['SCRIPT_NAME'], $i, $i);
}
}
return $naviLink;
}
function getNextLink() {
//次のページが存在する場合、次のページへのリンク
if ($this->maxPageNum > $this->pageNum + 1) {
return sprintf('<a href="%s?page=%d">Next</a> ', $_SERVER['SCRIPT_NAME'], $this->pageNum + 1);
}
}
function getPrevLink() {
//現在のページが0では無い場合、前のページへのリンク
if ($this->pageNum != 0) {
return sprintf('<a href="%s?page=%d">Prev</a> ', $_SERVER['SCRIPT_NAME'], $this->pageNum - 1);
}
}
}
if(isset($_GET['page'])){
$page = $_GET['page'];
}else{
$page = 0;
}
$pager = new TekitouPager('data.dat', 5,$page);
var_dump($pager->getPageData());
echo $pager->getPrevLink() . $pager->getNaviLink() . $pager->getNextLink();
2011/06/28 23:15 追記
とりあえず9JPの@buffbuffratさんから、次ページリンクの処理がこのままだとできないと指摘をいただいたため、慌てて修正しました。ありがとうございます。
変更箇所は、ファイルが何行あるのか調べるという部分です。
$file = new SplFileObject($dataFile);
//ページ数を計算
$count = 0;
foreach ($file as $line) {
$count++;
}
こんな感じです。
なにを変えたか
ページング自体のロジックは変更していません。ファイルを読み込む方法を変更してあります。元のソースは file() で全てを読み込み、配列に格納していましたが1000行も超えてくるとメモリ消費も馬鹿になりません。
そこで、SplFileObjectを使って、ファイルポインタを移動して、必要な行のみを取得しています。これであれば、メモリも最低限でいけます。
さすがに数万とかになってくるとポインタ移動だけで、けっこうな負荷になりますが、それでも全部読み込むよりはましだと思います。
実際にパフォーマンスを測ってみた
abで簡単にパフォーマンスを測ってみました。
| file() | SplFileObject | |
|---|---|---|
| 20行 | 1733 [#/sec] | 1653 [#/sec] |
| 500行 | 1180 [#/sec] | 1292 [#/sec] |
| 1,000行 | 844 [#/sec] | 1246 [#/sec] |
| 20,000行 | 40 [#/sec] | 490 [#/sec] |
ファイルサイズが大きくなるにつれてパフォーマンスの差も出てきますね。
[...] 改良 : PHPでのページング処理のサンプル | zaru blog [...]