【PHP】初回に生成したHTMLコードを再利用して処理を軽くする

HTMLコードを再利用してPHPの処理を軽くするブログ

PHPは動的サイト制作に使われると知りつつもまったく触れたことはありませんでした。ブログ開設後、やりたいと思ったことを実現するにはPHPが必須と知り、PHPとMySQLを勉強しました。そして、何個かの共通パーツを作ることができました。

現在、PHPを利用して以下を実現しています。

  1. ウェブサイトのパーツ化
    多くのページで表示する内容を共通パーツとして作成できます。PHPを変更することですべてのページの表示内容を変えることができます。
  2. 動的表示
    MySQLなどのデータベースと連携するなどしてアクセス毎に表示内容を変えられます。

今回は新しく何かを作った話ではなく、ファインチューニングの話です。アクセス毎にHTMLコードを生成するのをやめて処理を軽くしましょうという内容になっています。

先に書いておきますが、理論的には処理が軽くなるはずなのですが測定した読み込み速度には有意な差は確認できませんでした。とは言え、そんなに大変な作業をする訳ではないので対応しておいた方が良いかなと思っています。素人考えですので異論は認めます。

今まで作成してきたパーツ

せっかくですので今まで作成してきたパーツを今回の対応の対象、非対象関係なくまとめて紹介してみます。

にほんブログ村のバナー表示

ブログ村のバナー表示用の共通パーツです。アクセス毎にバナーの上のテキストをランダムで出し分けをします。

ランダムバナー
にほんブログ村バナー

動的表示内容の更新タイミング

  • テキスト:アクセスがあったとき

アクセス毎に変えるのが目的なので、当たり前ですね。今回の対応の対象外となります。

ランキングナビゲーション

日本株投資成績の記事からトップ3とワースト3のランキングを作成し、ナビゲーションを作る共通パーツです。

ランキングナビ
ランキングナビ

動的表示内容の更新タイミング

  • ワースト3の順位(確定):記事を投稿したとき
  • ナビの内容(不確定):ランキングに入る記事を投稿したとき
  • ナビの内容(不確定):ランキングに入っている記事のタイトルをリライトしたとき

記事を更新したタイミングで必ず生成するコードが変わります。記事投稿のタイミングでしか表示内容が変わらないのにアクセス毎に処理をしているため、今回の対応の対象となります。(記事タイトルのリライトは記事投稿のタイミングで更新で問題ないとします。)
なお閲覧中の記事がランキングに入っている場合は、タイトルの文言を変えているのでレコードごとにコードを持たせる必要があります。

サイコロジカルライン

12日間サイコロジカルラインを表示する共通パーツです。

サイコロジカルライン
サイコロジカルライン

動的表示内容の更新タイミング

  • なし

記事を投稿したタイミングで一度コードを生成すれば、他の記事が投稿されても影響がありません。作成時に一度だけ動的にコードを生成し、その後はそのコードを表示するだけという仕組みを取り入れてます(上記記事参照)。

サイコロジカルラインナビ

サイコロジカルラインを元にした12日間の勝敗をタイトルと共に見せるナビケーションの共通パーツです。過去だけではなく、未来の3日間も入れるようにしています。

サイコロジカルラインナビ
サイコロジカルラインナビ

動的表示内容の更新タイミング

  • ナビの内容(確定):ナビの対象となる未来の記事を投稿したとき
  • ナビの内容(不確定):ナビの対象となる記事のタイトルをリライトしたとき

過去分については基本的に変更はありません。記事投稿のタイミングでしか表示内容が変わらないのにアクセス毎に処理をしているため、今回の対応の対象となります。(先ほどと同じく記事タイトルのリライトは記事投稿のタイミングで更新)

対応内容

1回目のアクセス時に生成したコードをテーブルに格納しておき、2回目以降のアクセスではその格納されたコードを表示するというシンプルな対応です。やることは以下です。

  1. 生成されたコードが格納されるフィールドがNULLかどうかを判別
  2. NULLでなければそれを表示
  3. NULLならばコード生成し、生成したコードを表示&格納
  • 生成されたコード格納用にフィールドの追加が必要です
  • テーブルへレコード追加時に該当フィールドをNULLにします

コードの変更

さて、では前回作成したスクリプトに上記部分を追加していきます。

MySQLのテーブルに生成されたコードの格納フィールドとして「rank_nav」「psy_nav」(どちらもvarchar(2000)、初期値NULL)を追加しています。

ランキングナビ

ハイライト部分が追加した部分です。

<?php

$slug = get_post(get_the_ID())->post_name;

//初回のみhtmlコードを作成(2回目以降はrank_nav内のコードを出力)
if ( $code = $wpdb->get_var("SELECT rank_nav FROM $wpdb->stock_jp WHERE post_name = '$slug'")){
	echo $code;
}else{

	//トップ用code作成
	$code_top = '<ul class="rank-top">';

	  $num = 1;

	  //day_changeの上位3レコードを取得(結果は配列に格納される)
	  $results = $wpdb->get_results("SELECT * FROM $wpdb->stock_jp ORDER BY day_change DESC LIMIT 3");

	  foreach ( $results as $value ) {

	    //ランキングに7日以内の記事が入っているか    
	    if ($value->is_new) {
	      $new_mark = '<span class="rank-up-color">NEW!</span> ';
	    }else {
	      $new_mark = '';
	    }

	    //ランキングに閲覧中の記事が入っているか
	    if ($value->post_name === $slug) {
	      $title = '<span class="rank-up-color">本記事です</span>';
	    }else {
	      $title = $value->title;
	    }

	    $code_top = $code_top . '<li><a href="' . '/result/stock/' . $value->post_name . '/" id="rank-top' . $num . '"><div class="rank-num">第' . $num . '位 +' . number_format($value->day_change) . '</div><div class="rank-date">' . $new_mark . date('Y/n/j', strtotime($value->date)) . '</div>';
	    $code_top = $code_top . $title . '</a></li>';
	    $num++;
	  }

	$code_top = $code_top . '</ul>';


	//ワースト用code作成
	$code_bottom = '<ul class="rank-bottom">';

	  $num = 1;
	  $num_max = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->stock_jp");

	  $results = $wpdb->get_results("SELECT * FROM $wpdb->stock_jp ORDER BY day_change ASC LIMIT 3");


	  foreach ( $results as $value ) {

	    if ($value->is_new) {
	      $new_mark = '<span class="rank-down-color">NEW!</span> ';
	    }else {
	      $new_mark = '';
	    }

	    if ($value->post_name === $slug) {
	      $title = '<span class="rank-down-color">本記事です</span>';
	    }else {
	      $title = $value->title;
	    }

	    //idは最下位からrank-bottom1~3を付与
	    $code_bottom = $code_bottom . '<li><a href="' . '/result/stock/' . $value->post_name . '/" id="rank-bottom' . $num . '"><div class="rank-num">第' . $num_max . '位 ' . number_format($value->day_change) . '</div><div class="rank-date">'  . $new_mark . date('Y/n/j', strtotime($value->date)) . '</div>';
	    $code_bottom = $code_bottom . $title . '</a></li>';
	    $num++;
	    $num_max--;
	  }

	$code_bottom = $code_bottom . '</ul>';


	//htmlコードを生成
$code = <<<eof
<div class="ranking"><div class="rank-title">暴騰&amp;暴落日ランキング</div><div class="rank-date"><small><small>(期間:2019/6/24~)</small></small></div>
<div class="ranking-contents">
<!-- cocoonレイアウト2カラムを使用 -->
<div class="wp-block-cocoon-blocks-column-2 column-wrap column-2 column-2-2-1-1 layout-box"><!-- wp:cocoon-blocks/column-left -->
<div class="wp-block-cocoon-blocks-column-left column-left">


$code_top


<!-- /wp:cocoon-blocks/column-left --></div>
<!-- wp:cocoon-blocks/column-right -->
<div class="wp-block-cocoon-blocks-column-right column-right">


$code_bottom


<!-- /wp:cocoon-blocks/column-right --></div>
</div>
</div></div>

eof;


	echo $code;

	//rank_navにhtmlコードを書き込み
	$wpdb->update($wpdb->stock_jp, array('rank_nav' => $code), array('post_name' => $slug));
}
?>

ヒアドキュメント内にインデントを入れるとエラーになります。

サイコロジカルラインナビ

ハイライト部分が追加した部分です。

<?php

//offsetの値を取得(閲覧中の記事が最新から何番目か)
$slug = get_post(get_the_ID())->post_name;
$offset = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->stock_jp WHERE post_name >= '$slug' ORDER BY post_name DESC") - 1;

//テーブルにレコードが追加されていない場合は何も生成しない
if ($offset == -1) {
	echo '';
} else {
	//初回のみhtmlコードを作成(2回目以降はpsy_nav内のコードを出力)
	if ( $code = $wpdb->get_var("SELECT psy_nav FROM $wpdb->stock_jp WHERE post_name = '$slug'")){
		echo $code;

	}else{
		//未来の記事があればmax3件まで対象に含める
		if ($offset > 3) {
			$limit = 15;
			$offset = $offset - 3;
		} else if ($offset <= 3) {
			$limit = 12 + $offset;
			$offset = 0;
		}

		//offsetした位置から12~15日ぶんのレコードを抽出
		$results = $wpdb->get_results("SELECT * FROM $wpdb->stock_jp ORDER BY post_name DESC LIMIT $limit OFFSET $offset");

		foreach ( $results as $value ) {

			//白丸と黒丸(数字付き)を生成
			$continuous_days = $value->continuous_days;
			$number = explode('.', $continuous_days);

			if ($number[0] > 0) {
				$cir_num = 11 + $number[0];
				$cir_num = '&amp;#93' . $cir_num;
			} else {
				if ($number[0] > -10) {
					$cir_num = 1 + abs($number[0]);
					$cir_num = '&amp;#1010' . $cir_num;
				} else if ($number[0] = -10) {
					$cir_num = '&amp;#10111';
				} else {
					$cir_num = 40 + abs($number[0]);
					$cir_num = '&amp;#94' . $cir_num;
				}
			}


			//天気アイコンを生成
			switch ($value->weather) {
				case 1:
					$weather = '<i class="wi wi-day-sunny"></i>';
					break;
				case 2:
					$weather = '<i class="wi wi-day-cloudy"></i>';
					break;
				case 3:
					$weather = '<i class="wi wi-cloudy"></i>';
					break;
				case 4:
					$weather = '<i class="wi wi-rain"></i>';
					break;
				case 5:
					$weather = '<i class="wi wi-thunderstorm"></i>';
					break;
			}


	    //title生成(閲覧中の記事は別処理)
			if ($value->post_name === $slug) {
				$title = '←イマココ';
			}else {
				$title = '<a href="' . '/result/stock/' . $value->post_name . '/">' . $value->title . '</a>';
			}


			//結合(新しい記事が下に来る)
			$code = $cir_num . ' ' . $weather . ' ' . $title . '<BR>'. $code;
		}

	  //サブタイトル生成
		if ($limit == 12){
			$subtitle = '<small><small><small>(過去11日)</small></small></small>';
		} else {
			$subtitle = $limit - 12;
			$subtitle = '<small><small><small>(過去11日+未来' . $subtitle . '日)</small></small></small>';
		}

		//コード生成
		$code = '<p><span class="related-entry-heading"><B>サイコロナビ</B> ' . $subtitle . '</span><div class="psy_nav">' . $code . '</div></p>';

		echo $code;

		//psy_navにhtmlコードを書き込み
		$wpdb->update($wpdb->stock_jp, array('psy_nav' => $code), array('post_name' => $slug));

	}
}
?>

読み込み速度の改善効果

Google InsightsやChromeの開発ツールを利用して変更前と変更後の読み込み速度の比較を行いましたが、有意な差は確認できませんでした。
ただ処理が少なくなるので理論的には早くならないはずがないと信じてます。信じる者は救われるはずです。

あとがき

作ったものの振り返りをやりたかったので、本記事でそれができてちょうどよかったです。肝心の読み込み速度の高速化がデータとしては示せなかったのは残念でした。おそらく大して重い処理をやっているスクリプトではないので有意な差が見られなかったのでしょう。

コメント

タイトルとURLをコピーしました