Web系のこととかー。

ページング…?

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>&nbsp;', $_SERVER['SCRIPT_NAME'], $i, $i);
            }
            else {
                $naviLink .= sprintf('<b><a href="%s?page=%d">%d</a></b>&nbsp;', $_SERVER['SCRIPT_NAME'], $i, $i);
            }
        }
        return $naviLink;
    }

    function getNextLink() {
        //次のページが存在する場合、次のページへのリンク
        if ($this->maxPageNum > $this->pageNum + 1) {
            return sprintf('<a href="%s?page=%d">Next</a>&nbsp;', $_SERVER['SCRIPT_NAME'], $this->pageNum + 1);
        }

    }

    function getPrevLink() {
        //現在のページが0では無い場合、前のページへのリンク
        if ($this->pageNum != 0) {
            return sprintf('<a href="%s?page=%d">Prev</a>&nbsp;', $_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]

ファイルサイズが大きくなるにつれてパフォーマンスの差も出てきますね。

§357 · 6月 28, 2011 · プログラミング_PHP · · [Print]

1 Comment to “改良 : PHPでのページング処理のサンプル。”

  1. [...] 改良 : PHPでのページング処理のサンプル | zaru blog [...]

Leave a Reply