ページング…?
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 [...]