PHPではprint_rでArrayの内容を出力できますが、smartyの場合どうしたらよいものかと。まぁループして書き出せばよいのですが、それは面倒だなと。
{$array|@debug_print_var}
これで出力できます。簡単ですね。
最近ものすごく久しぶりにPHPを書いていますが、Array関連のメソッドが非常に豊富で、便利だなぁと。
PHPではprint_rでArrayの内容を出力できますが、smartyの場合どうしたらよいものかと。まぁループして書き出せばよいのですが、それは面倒だなと。
{$array|@debug_print_var}
これで出力できます。簡単ですね。
最近ものすごく久しぶりにPHPを書いていますが、Array関連のメソッドが非常に豊富で、便利だなぁと。
前回のエントリが結局フレームワークの話になってしまったため、新しいエントリを書きました。
同じような処理をさせた場合、どの言語が一番早いのか。非常に気になるところでありますが、試したことがありませんでした。今回試してみたところ、意外な結果が出たのです。
下の方に書いたそれぞれのプログラムを実行した結果の、プログラム内部で計測したミリ秒を比較してます。
| PHP | Ruby | Python |
|---|---|---|
| 2.80秒 | 0.36秒 | 0.93秒 |
3回計測した平均です。同じ処理をさせるプログラムを書いたつもりですが、本当にフェアなものになっているのか正直自信がありません。そもそもPHPはWebアプリを主な目的としているとのことなので、こういう処理は得意としていないのかもしれない。
また、それぞれのプログラムのループ内2行目、文字列連結の部分をコメントアウトして実行してみると、これまた意外な結果が出ました。
| PHP | Ruby | Python |
|---|---|---|
| 0.07秒 | 0.06秒 | 0.39秒 |
PHPは文字列連結が苦手なんだろうか。暗黙的な型変換にコストがかかるのだろうか、等々考えてしまいます。それとも秒を求める部分がネックなんですかね。その辺は今後追っていきます。
ただ、これまでPythonの方がRubyより早い、と思っていたために自分の無知さに猛烈に恥ずかしい思いをしています。
実際にMySQLと連携するバッチを書いたときにはRubyの方が遅かったり、Railsアプリがもっさりだったり、「速い」という印象がまったくありませんでした。が、それはある特定の面しかみていない上での思い込みだったのかもしれません。
これはRailsが遅いのか、もしくはMySQL/Rubyが遅いのか。当時の書き方がマズかったのか。今後、いろんなケースでこういった比較をしてみようかと。
今回の検証がすべてではないし、これが答えだとも思っていません。また、そういう意図を含んだエントリではありません。今回の検証だって、特定の面しか見ていません。が、あまりに意外な結果だったため、自戒の念を含めてブログに書きました。
「こう書くともっとフェアだよ」「こういうテストの方がいいんじゃない」等、アドバイスいただけるとうれしいです。
フレームワークまで含めた検証した方が現実的なのだろうか。。。
#!/usr/bin/php
<?
function microtime_float()
{list($usec, $sec) = explode(” “, microtime());
return ((float)$usec + (float)$sec);}
$_start = microtime_float();
$_sec = date(’s’);for($i=1;$i<100000;$i++)
{$_val = (mt_rand(0, 100) + $i) / $i;
$_str = $_val.date(’s’);}
echo microtime_float() – $_start;
?>
Ruby
#! /usr/local/bin/ruby
i=1
_start = Time.now99999.times do
_val = rand(100) / i
_str = _val.to_s + Time.now.sec.to_s
i += 1end
p (Time.now – _start).to_f
Python
#!/usr/bin/python
# -*- coding: utf-8 -*-
import datetime
import random_start = datetime.datetime.now()
for i in range(1, 100000):
_val = random.randint(0, 100) / i
_str = str(_val) + str(datetime.datetime.now().second)print datetime.datetime.now() – _start
CPU:Xeon 1.86GHz
メモリ:2GB
OS: CentOS5.4 32bit
PHP:5.2.11
Ruby:1.8.7
Python:2.5.2
よく「スパゲッティの元だ」みたいな扱われ方をしますが、三項演算子はスパゲッティとは関係ないんじゃないかなぁと個人的には思うわけですよ。
確かに多用し過ぎると可読性が著しく下がりますが、それがイコールスパゲッティになるとは思っていません。
やっぱり書く人に依存、っていうことですよね。
$_page = (is_numeric($_GET["page"]))? $_GET["page"]: 1;
このまま使ってはいけない例ですが、
「pageっていうGETのパラメータが数値なら$_pageにはその値、数値じゃないなら$_pageには1を代入しなさい」
っていう内容です。
if(is_numeric($_GET["page"])){
$_page = $_GET["page"];
}else{
$_page = 1;
}
と同じ結果ですね。
クエリで
load data local infile ‘ファイルパス’ into table テーブル名;
を実行するだけなのですが、「local」をつけないと動いてくれなかったのでメモ。SSHでログインしていたときは「load data infile」だけでインポートできていたので、気がつかずに苦労しました。
はっきりいって、やっぱりRubyは遅いです。Railsじゃなくて、Rubyが遅いです。Rubyでループしまくってデータをインポートするバッチを書いたら、C#で同じ処理をさせたときの倍近くかかりました。(正確に計測していないので倍は言いすぎだと思うが、体感できるぐらい遅かった。今度PHPで同じコードを書いてみよう)
いわれてみれば書いてて気持ちいいし、Railsはらくちんです。しかし、ここまで遅いとは思っていなかった。ただ、遅いといってもフツーのWebアプリを開発する分にはそれほど大差は出ないのかもしれません。それでもやっぱりループ処理は遅いなぁ。イテレータのおかげでらくちんではあるのですが。
ORマッパーは、便利ですがやはり不安を常に感じてしまいます。ループ処理するときにはORマッパー任せにしないでfind_by_sqlで自分でSQLを書いちゃいます。そうしないと、100回のループで100件の問い合わせをされちゃいます。ここは外部結合使ってごっそり取ってきて欲しかった。まぁ、MySQLは外部結合するよりクエリ連打した方が早いからいいのかな。
ただし、ルーテイングは便利です。コントローラとアクションの管理がラクなので、あとからソースを追うときに非常にラクです。さらに、MVCの管理がすっきりしてます。
「それだけならCakePHPでもいいじゃないか」といわれそうですが、CakePHPはRubyonRailsより遅いというベンチを誰かのブログで拝見しました。いやー、アレ以上遅いのはさすがにパスかな。symfonyも同様みたいです。
小規模サイトで開発メンバーの入れ替わりがあるなら、フレームワークは必須でしょう。中規模以上になってもハードウェアに予算投入で解決できるならそれほど問題にはならないと思います。
予算が限られ、自社内コンテンツみたいに開発メンバーが限定されるのであれば、ピュアなPHPとSmarty、URLをきれいにしたければ(GETにだらだらつけたくなければ)mod_rewriteを使えばよいかと。
自社内コンテンツであっても、メンテナンスなどを考えるとフレームワークを導入した方がいい気もするのですが、サイトの成長計画と相談ですかねぇ。
あ、言語の話じゃなくてフレームワークの話になってきちゃった。
FPDIを利用します。「フリーで使っていいよ」と書いてあるのにPayPalのボタンが置いてあるのは、寄付はしてねっていうことですよね。会社のプロジェクトで利用することになったら経費で寄付してみようかと。
require ‘../var/fpdf/fpdi.php’;
$temp_pdf= new FPDI();
$_page = $temp_pdf->setSourceFile(‘../var/hoge.pdf’);
unset($temp_pdf);for($i=1;$i<=$_page;$i++)
{
$_write_pdf = new FPDI();
$_write_pdf->setSourceFile(‘../var/hoge.pdf’);
$_tmp_info = $_write_pdf->importPage($i);
$_write_pdf->addPage();
$_write_pdf->useTemplate($_tmp_info);
$_write_pdf->Output(“hoge_”.$i.”.pdf”,”F”);
unset ($_write_pdf);
}
unsetにはあまり意味はない、というかムダかもしれません。closeやdisposeが見当たらなかったので微妙に気持ち悪かったから入れただけです。解放してくれているのかなぁ。
ページ数の取得のために一度テンプレートとして読み込み、それからページ数分でループしてます。ループ処理の中で「テンプレートファイルのiページ目だけ読み込んでファイル書き出し」を繰り返しています。
これでやりたいことはできたのですが、なんかメソッド一発で分割してくれるのがありそうで怖い。あったらどなたか教えてください。
FPDIは1.2、FPDFは1.53、PHPは5.2、WindowsXP上のApache2.0で動作確認しました。
「sprintf」を使うか「str_pad」を使うかが悩みどころです。今までは大して気にしてなかったのですが、どうやら「str_pad」の方が早いらしい。
ということで検証したのですが、あんまり変わんない。。。
まぁ所詮20万回程度のループだと大して差は出ないかな。とはいえ、実開発でそこまで大きな処理させるとも思えないし、ここはどっち使っても差はないということにしておきましょう。
使いやすい方でいいや。
str_pad使って「$_counter」という文字列を10桁に「0」で桁埋め。左側を埋める。
str_pad($_counter,10,’0′,STR_PAD_LEFT)
sprintfを使って「$_counter」という文字列を10桁に「0」で桁埋め。
sprintf(“%010d”,$_counter)
「{」と「}」はSmarty側で変数の判定に使うので、JavaScriptのfunctionを記述するとSmartyに怒られてしまいます。まぁ当然の結果です。
で、
{literal}
<script language=”javascript”>
function hoge()
{
alert(‘hoge’);
}
</script>
{/literal}
という風に「{literal}」でスクリプトブロックをくくると怒られないで済みます。
$_SERVER['HTTP_X_DCMGUID'];
UIDとは別物の7桁半角英数字。上記はPHPでの例です。
ドコモも勝手サイトを無視できなくなってきたんでしょうね。開発屋としてはありがたい限りです。ただ、きっと完全にユニークな値であることは保障されないんだろうな。UID同様、使いまわすんだろうな。注意せねば。
「生産性をうん倍アップ」なんてよく聞いたのですが、ほんとにそこまであがるのかなぁ。
確かにテンプレートとか勝手に作ってくれて便利なのかもしれないけど、その分隠蔽化されちゃってる気がしてよけいに調べるのに時間がかかったりしてます。
慣れるとそのへんはあうんの呼吸で、手放せないくらい便利になっちゃったりするのかなぁ。
ただ、いろんなとこでパフォーマンスへの懸念は耳にしました。何はともあれ遅いらしい。もっさりレベルではなく、遅いらしい。RoRは処理速度は二の次、エンジニアが気持ちよくかけることを追求したらしいのですが、これだと運用入った瞬間に気持ちよくなくなるような気がする。。。
あと、個人的にORマッパーって嫌い。SQLって、書き方ひとつでパフォーマンスに影響出るじゃないですか。やっぱりSQLは自分の手でごりごり書きたいわけですよ。
古いんだろうなぁ、これが。
やはり、今にだPHP+Smarty+PostgreSQLが僕の中で最強です。PythonやRoRはもうちょっと様子見だな。。。