PHP/microtimeで処理の実行時間(マイクロ秒単位)を知る

目次

■PHPでタイムスタンプを得るための関数やクラスにも,「date」「time」「Datetime」「microtime」などいろいろある

たとえば、開発時、処理速度を細かく計測して、すこしでもスムーズなコードを作成したい方にとっては、「タイムスタンプでの処理時間=各処理の実行時間計測」は非常に便利です。 学校などのサーバによっては、処理の実行時間があまりにかかるものは、サーバから切断されるなどの設定になっているところもありますよね。 ということもあり、各パートや処理の部分ごとに、この「秒以下の正確さ」のある計測時間=「教授!ここが改善しました!」という実績が欲しいのです! PHPでさまざまなタイムスタンプを得たいとき、こんな方法が使えます。

■PHPの関数「microtime」なら、マイクロ秒までが取得可能!

プログラミング言語PHPで使う関数「microtime」

これは、現在時刻を「マイクロ秒(=ミリ秒取得OK!)」までunix時間(=unix timestamp)で測定した返り値を戻してくれます。

ご存知の通りPHP5.0.0以降ではfloat表示をカバーしました。 そこで関数「microtime」もこれまでよりもとても扱いやすくなったのです。

■PHP5以降で使いやすくなった関数「microtime」とは?

(PHP 4, PHP 5, PHP 7) microtime — 現在の Unix タイムスタンプをマイクロ秒まで返す
mixed microtime ([ bool $get_as_float = false ] ) microtime() は、現在の Unix タイムスタンプをマイクロ秒単位で返します。 この関数は、gettimeofday() システムコールをサポートする オペレーティングシステムでのみ使用できます。

ご存知の通り、gettimeofday() システムコールをサポートする オペレーティングシステムは、WindowsやLinuxなど。 これらで使用することができます。

PHP microtime関数の使い方その1:第一引数を指定しないと、「msec+sec」形式で出力

たとえばここで、第一引数を指定しなければ、【msec&sec】のスタイルで返り値を表示します。 このとき返される値は『文字列』です。

【1】 echo microtime(); 【2】 echo microtime(false); の2つのPHPのいずれにおいても、実行されると、 GMT: 2018年7月22日 07:44:38 Sunday JST: 2018年7月22日 16:44:38 日曜日 の場合 「0.12120200 1532245478」のような値を返します。 スペース右が秒部分までの(1970年1月1日0:00:00からの)秒数、 それ以下の、このプログラムを実行し始めた時間までの秒以下が、スペース左=マイクロ秒部分です。

PHP microtime関数の使い方その2:第一引数をfloatで指定すると、「sec.msec」形式で出力

第一引数が指定できるのは、PHP 5以降。 true=return_float=浮動小数点型フラグとなっています。

そのため、echo microtime(true); とすると たとえば、 GMT:「2018年7月22日 07:44:38.121 Sunday GST: 2018年7月22日 16:44:38.121 日曜日であれば 「1532245478.121」のような値を返します。 これはシステムをあまり使い慣れておらず、事務系ツールだけを使っている人でもわかりやすい数字。

■PHPの関数「microtime」をもっとわかりやすく表示するにはどうすればいいの?

【1】第一引数なしで取得した値の変換 さて、ちょっと面倒な形式で出力されたmicrotime どんなふうに変換すれば、このただの数字の羅列の様に見えるものが、見やすくなるのでしょうか?

こちらでは、explodeで分解した数字をつかって、表示書式を成型してみました。 //ここから //PHPの関数microtimeでこのコード実行開始時の時間をunix取得 list($microsec, $Unixdatetime) = explode(" ", microtime()); $onlysec = $microsec + date("s", $Unixdatetime); echo date("Y年m月d日 g:i:", $Unixdatetime).$onlysec; //ここまで //PHPの関数microtimeでこのコード実行開始時の時間をunix取得 とすると、 microtime=0.12100100  1532245478 のとき 表示は、「2018年07月22日 16:44:38.121001」 となります。

【2】第一引数をtrueとして、浮動小数点型で取得した値の変換 生まれ変わったPHP5.0以降の「microtime」をさらに見やすくするには、ひとがより見慣れたスタイルに変換&書式を成型するのがBetter! こんな変換方法はいかがでしょうか?

//ここから //PHPの関数microtimeでこのコード実行開始時の時間をunix取得 echo date(”Y-m-d H:i:s”) .”.”. substr(explode(”.”,microtime(true))[1], 0, 3); //ここまで //PHPの関数microtimeでこのコード実行開始時の時間をunix取得 とすると、 microtime=1532245478.121 のとき 表示は、「2018-07-22 16:44:38.121」 一度で変換していますが、単に桁数だけを比較しているときよりも、短い処理の実行時間にもかかわらず、ぐっと見やすいですね。

たとえば多数の処理を行うプログラムの中で、頻繁に直接microtimeで値を取り出すというのでなければ、処理の実行時間にも変換の実行時間にもあまり負担は発生しないかもしれません。 変換時の表示桁数含め、それぞれ【1】と【2】の日月日表示などにさらに工夫をしても見やすいかもしれません。

■実はPHPのマイクロタイムの桁数には、ちょっと注意したいことがある!

Unix時間のタイムスタンプは、もともと・・・  ・日付の年から秒まで含めた含めた整数の桁数で 10桁  ・小数部分の桁数で 6桁    (※マイクロ秒=100万分の1秒(10−6=1/1,000,000秒のため、同じ桁数以上が必要)) ですが、PHPの浮動小数点型には、実はちょっとした「精度」的な落とし穴があります。

float の大きさはプラットフォーム依存です。 ただし、通常はおよそ 10 進数で 14 桁の精度があり、最大値は ~1.8e308 (これは 64ビット IEEE フォーマットです) となります。
警告 浮動小数点数の精度 浮動小数点数の精度は有限です。 システムに依存しますが、PHP は通常 IEEE 754 倍精度フォーマットを使います。 この形式は、1.11e-16 のオーダーでの丸め処理で誤差が発生します。 複雑な算術演算をすると、誤差はさらに大きくなるでしょう。 そしてもちろん、 いくつかの演算を組み合わせる場合にも誤差を考慮しなければなりません。
さらに、十進数では正確な小数で表せる有理数、たとえば 0.1 や 0.7 は、 二進数の浮動小数点数としては正確に表現できません。 これは、仮数部をいくら大きくしても同じです。 したがって、それを内部的な二進数表現に変換する際には、どうしても多少精度が落ちてしまいます。 その結果、不思議な結果を引き起こすことがあります。 たとえば、 floor((0.1+0.7)*10) の結果はたいてい 7 となるでしょう。 おそらくは 8 を想定していらっしゃるでしょうが、そのようにはなりません。
これは、(この計算結果の) 内部的な値が 7.9999999999999991118... のようになっているからです。 よって、小数の最後の桁を信用してはいけませんし、 小数を直接比較して等しいかどうかを調べてはいけません。 より高い精度が必要な場合には、 任意精度数学関数または gmp 関数を代わりに使用してください。

たとえば証券取引所やオークションのような、マイクロ秒内でどれだけの取引が発生するかといったことが問われる業務では「PHPは適切とはいいがたい」もののようです。 ですが、プログラム開発中のプログラム自体の実行時間計測や、情報などの処理や表示変換などに要した時間計測といったざっくりとした時間計測では、かなり使えそう。 そんなことも踏まえて、業務の中で、PHP の関数「microtime」をどんな風に活用すればよいのか考えてみましょう。

■PHPの関数「microtime」をつかって、業務をわかりやすく、うまく活用するにはどうすればいいの?

さて、microtimeを使って得た数字を、業務でどうやって使っていけばいいか考えてみましょう。

たとえば、microtime表示の日に対しての月末締め日行事や、丸3日後までの事務処理や引き当て確認日表示などにはstrtotimeが使える

たとえば、strtotimeを使えば、「絶対日時」と「相対日時」で指定・表示させることができます。 そしてこの時間に対して、下の単位で、「●日後」や「●秒後」などの時間をプラスした演算表示も可能です。 year年 month月 week週 day日 hour時間 minute分 second秒

//ここから //現在のUNIX TIMESTAMP $Nowtimedate = strtotime( Datetime(”Y/m/d H:i:s”) ) ; //ここでは現在($Nowtimedate)から48時間後のUNIX TIMESTAMPを取得 $timestamp = strtotime( ”+48 hour” , $Nowtimedate ) ; echo $timestamp ; //ここまで //現在のUNIX TIMESTAMP

これで表示される、Datetimeと、先ほどのmicrotimeで取得した日付での一致による、複数人での入出力処理によるレコードの有効性や優先順などを判別させるといった使い方。 Unix時間をStrtotimeで計算して i) 上記のような単純な48時間後などの計算や ii) 時刻を夜0時0分1秒などに設定し、そこから48時間後などとして、「カレンダーの2日後」を必ず示すなどの使い方も可能です。

王道!さまざまなコードによる処理の開始時間と終了時間=「処理の所要時間」を記録したい

プログラムの開始時間、終了時間、処理時間を表示させる例をご紹介します。
<?php $start_time=microtime(true); echo ”開始時間: ”.formatMicrotime($start_time,’Y-m-d H:i:s’).”<br>”; //メイン処理 $end_time=microtime(true); echo ”終了時間: ”.formatMicrotime($end_time,’Y-m-d H:i:s’).”<br>”; $syori_zikan=$end_time - $start_time; echo ”処理時間:”.formatMicrotime($syori_zikan).”秒<br>”; exit(); function formatMicrotime ( $time, $format = null ) { if (is_string($format)) { $sec = (int)$time; $msec = (int)(($time - $sec) * 100000); $formated = date($format, $sec). ’.’. $msec; } else { $formated = sprintf(’%0.5f’, $time); } return $formated; } ?>
処理結果は次になります。 なお上記の function formatMicrotime()は*1を参考にさせていただきました。 開始時間: 2010-01-12 00:51:40.54924 終了時間: 2010-01-12 00:51:40.54937 処理時間:0.00013秒

これを処理の前後に繰り返せばいいだけです。

こういったものも、いつも関数化して、呼び出すようにしておいても良いかもしれません。

もうちょっと処理を早くしたいんだけど・・・「microtime」のほかに、関数や方法はないの?

「micerotime」のほかにも、こんな方法が使えます。

タイムスタンプに使えそう?なPHP【date】

(Ver4/5/7) ローカルの日付/時刻を書式化する

string date ( string $format [, int $timestamp = time()] )
指定された引数 timestamp を、与えられた フォーマット文字列によりフォーマットし、日付文字列を返します。 タイムスタンプが与えられない場合は、現在の時刻が使われます。 つまり timestamp はオプションであり そのデフォルト値は time() の値です。

ちなみに、PHP5.2.2以降では、パラメータに「u」をつけることで、マイクロ秒を表しますが、integer型のため、常に「000000」が吐かれます。

たとえば、 「echo date(”Y-m-d H:i:s.u”); #」 では 「2015-03-03 11:11:11.000000」 を返してきます。

タイムスタンプに使えそう?なPHP【Datetime】

(Ver. 5.2.1以降, 7)指定した書式でフォーマットした日付を返す

オブジェクト指向型 public string DateTime::format ( string $format ) public string DateTimeImmutable::format ( string$format ) public string DateTimeInterface::format ( string$format )
手続き型 string date_format ( DateTime $object , string $format)
パラメータ ¶ object 手続き型のみ: date_create() が返す DateTime オブジェクト format date() が理解できる書式指定文字列。 返り値 ¶ 成功した場合にフォーマット済みの日付文字列、失敗した場合に FALSE を返します。

関数「Date」と同じ理由で、「Datetime」 クラス(5.2.0と7) を使っても、日付時刻でマイクロ秒まで表示させると「000000」。

「$today = new DateTime(); echo $today->format(’Y-m-d H:i:s.u’); # 」 とすると 「2015-03-03 11:11:11.000000」

タイムスタンプに使えそう?なPHP【time】

(Ver.4,5,7)

現在のUnixタイムスタンプを返す

int time ( void )
Returns the current time measured in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).

表示方法は一つ下でご紹介しますが、たとえば現在時刻が2018/07/22 16:44:38 なら 1532245478 が出力されます。

こちらももともとがミリ秒までは取得できないもの。 ということで、同じく表示桁数が足りずにNG。 いずれもこの関数などだけでは、値を変換するどころか取得自体ができないのでNG。

出典:pixabay.com

■【蛇足ですが】timeや$_SERVER[’REQUEST_TIME’]を使ってみると、UNIX時間が取得できる!~そもそもUNIX時間とは?

出典:pixabay.com

ちなみに先ほどの関数「time」の英語の説明文にあるように、Unixタイムスタンプ(unix timestamp)というのは、よく「UNIX時間」などとも呼ばれているもの。 「『UTC (=協定世界時)という、原子時系の調整された基準時刻』でいう『1970年1月1日の0時0分0秒を基準点』にした経過秒数」を示しています。 長いですね、お分かりいただけるでしょうか。

手っ取り早く言えば、「システム的な1970年1月1日の0時0分0秒からの経過秒数が数字で単に書かれているもの」です。 関数の「time()」で取得できるのは、このプログラムを起動した時点での、UNIX時間です。 ちょっとやってみましょうか?

// UNIX時間を[$starttime]に格納する $starttime = time() ; // いったん格納した[$starttime]の値をそのまま出力表示させてみる echo $starttime ;

たとえば 現在が GMT: 2018年7月22日 07:44:38 Sunday JST: 2018年7月22日 16:44:38 日曜日 なら 1532245478  が出力されます。

出典:pixabay.com

■PHPの関数 microtime についてご紹介しました

出典:pixabay.com

いかがでしたか? PHP の関数microtimeをはじめ、日付時間取得系のいろいろな「基本関数など」をご紹介しました。

なかでも<microtime> ・プログラムの処理スピード改善などの計測面 ・アクセス数が多い、業務での購買や在庫割り当て系システム などでは、タイミングや細かな計測時間重視のため、microtimeが。 それ以外、たとえば、あまりアクセス数のない、一日10件程度更新するといったデータベースであれば、それ以外にご紹介した関数などで十分。 処理スピードやシステム負荷も考えながら、適切なものを使い分けたいものです。