2012年1月22日日曜日

array_merge()と演算子「+」

phpで配列を結合する関数がある。「array_merge()」だ。

よく使うパターンはこんなシーン。

$a = array_merge($a, $b);

$aと$bが連想配列なら同じことを

$a = $b+$a;

と書ける。
足し算だが「+」演算子の左右の変数を入れ替えると結果が変わってしまう。
共通のキーがあった場合に、上書きをしないからだ。

$a=array(
 'x'=>'aX',
 'y'=>'aY',
);
$b=array(
 'y'=>'bY',
 'z'=>'bZ',
);

だった場合、
$a+$b
array(
 'x'=>'aX',
 'y'=>'aY',
 'z'=>'bZ',
);
となり、
$b+$a

array(
 'x'=>'aX',
 'y'=>'bY',
 'z'=>'bZ',
);
になる

$aと$bに共通のキーがないか、共通だった場合、$aを採用するならば
$a += $b;
と書くことができる。

連想配列の変数名は長めになることが多いのでこの書き方ができればありがたいが、
ここまで短く書けるシーンにあまりであったことがないのが残念。
でもこうして整理してみると、パラメータ$aをデフォルト値$bで補完する場合に使えそうだなあ。

$a, $bが通常の整数をキーに持つ普通の配列だった場合、「+」演算子の挙動はarray_mergeの挙動と著しく違うので知らないととまどう。
array('a1','a2','a3')+array('b1','b2','b3')
の結果はどうなるか?

array('a1','a2','a3')
となる

2012年1月18日水曜日

Bloggerでコード整形を行う


Bloggerに張っているソースコードやコマンドの実行結果等が見にくいので、下記のブログを参考にデザインを変更してみた

seiji's 十八番: [SyntaxHighlighter] bloggerに整形済みテキスト、プログラムソースコードなど...

SyntaxHighlitghterは以前、ExtJSでSVNビューワを作ったときに使ったことがあったので久しぶりに使ってみた。

やることは、上記のリンクに書いてある通り。ただ、使用するブラシの種類が違っていたのでそこだけ、選択を変えた。
現在使っていないプログラミング言語はばっさり捨て、テキスト用に「Plain」をdiff用に「Diff」を追加した。「Xml」は外しかけたが、htmlを整形するために必要だった。

差し込んだコードは以下の通り。

<!--ここからsyntaxHighlighterをコピペした-->
<link type='text/css' rel='stylesheet' href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' />
<link type='text/css' rel='stylesheet' href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushDiff.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' />
<script type='text/javascript' src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' />
<script language='javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.all();
</script>
ついでにメインのカラムの横幅を少し広げて表示できる桁数を増やした
-      <b:variable default='960px' name='content.width' type='length' value='860px'/>
----
+      <b:variable default='960px' name='content.width' type='length' value='1000px'/>

2011年11月8日火曜日

strftimeで日付がずれる

もしかしたら有名な話なのかもしれませんが、今日 スケジュールの画面のデモをphpで作っていたときにちょっとはまった。 クライアントにイメージをつかんでもらうための簡単なカレンダを phpでループさせて作っていたのだが、デモプログムの一部で、
date_default_timezone_set('Asia/Tokyo');
$base = strtotime('2011-11-01');
$days = explode(',', '日,月,火,水,木,金,土');
for ($i=0; $i<30; ++$i) {
 $date = $base+24*60*60*$i;
 $mmdd = strftime('%m/%d', $date);
 $day = $days[strftime('%w', $date)];
 echo "<br>$i: $mmdd($day)";
}

みたいに、今月の頭からループで24時間づつ増やしながら日付を表示させて、カレンダの日付の部分を表示させようとしたら、想定外の出力に!

0: 11/01(火)
1: 11/02(水)
2: 11/03(木)
3: 11/04(金)
4: 11/05(土)
5: 11/06(日)
6: 11/06(日)

7: 11/07(月)
8: 11/08(火)
9: 11/09(水)
10: 11/10(木)
: 
打ち合わせ開始まで30分しかなかったので、軽いパニックに。
誤差が蓄積されたような動きであったので、とりあえず、その場は
$base = strtotime('2011-11-01 14:00');
変更したところ、想定の出力で動き、残りの部分のコーディングに戻ることができた。

気になったので、今、「夏時間」をwikipediaで調べたら、


アメリカ合衆国(一部除く。前述のとおり2007年から次のように変更され実行されている)、カナダ(一部除く)、メキシコ(一部除く) - 3月第2日曜日午前2時〜11月第1日曜日午前2時(現地時間基準。開始日には2時が3時になり(1時59分59秒の次が3時00分00秒)、終了日は2時が再度1時(1時59分59秒の次が1時00分00秒)になるため、開始日は1日が23時間、終了日は逆に25時間になる)
と、アメリカでは11/6は25時間あることがわかった。ちなみに前のスクリプトに時間まで表示してみると、
0: 11/01 00:00(火)
1: 11/02 00:00(水)
2: 11/03 00:00(木)
3: 11/04 00:00(金)
4: 11/05 00:00(土)
5: 11/06 00:00(日)
6: 11/06 23:00(日)

7: 11/07 23:00(月)
8: 11/08 23:00(火)
9: 11/09 23:00(水)
10: 11/10 23:00(木)
11/6の00:00に24時間を足すと、11/6の23:00になっている。


ああ、すっきり!!、でもさ、夏時間のない'Asia/Tokyo'のロケールのはずじゃん。まいっか。いや、よくないな、よくない。
ここで、デジャヴが、どっかの環境で'Asia/Tokyo'が効かなくて、GMT-9って指定したことあったっけ。

 date_default_timezone_set('Etc/GMT-9');
 $base = strtotime('2011-11-01');
 $days = explode(',', '日,月,火,水,木,金,土');
 for ($i=0; $i<30; ++$i) {
  $date = $base+24*60*60*$i;
  $mmdd = strftime('%m/%d  %H:%M', $date);
  $day = $days[strftime('%w', $date)];
  echo "<br>$i: $mmdd($day)";
 }
 結果は
0: 11/01 00:00(火)
1: 11/02 00:00(水)
2: 11/03 00:00(木)
3: 11/04 00:00(金)
4: 11/05 00:00(土)
5: 11/06 00:00(日)
6: 11/07 00:00(月)

7: 11/08 00:00(火)
8: 11/09 00:00(水)
9: 11/10 00:00(木)
10: 11/11 00:00(金)
と、よしっ!きれいだ。ってなんでAsia/Tokyoと結果が違うの?
あ、そっか。日本って震災の節電の関係で夏時間設定されたんだっけ。
なんか違う。眠いからに違いない。寝よう。

よし、リフレッシュ。

ソースを少し変えてタイムゾーンを変えて流せるようにした。

echo "<pre>\n";
printDays('UCT');
printDays('Etc/GMT-9');
printDays('Asia/Tokyo');
printDays('America/New_York'); 
function printDays($timezone) {
echo "timezone:$timezone\n";
date_default_timezone_set($timezone);
$base = strtotime('2011-11-01');
for ($i=4; $i<8; ++$i) {
$date = $base+24*60*60*$i;
$mmdd = strftime('%m/%d  %H:%M', $date);
echo "$i: $mmdd\n";
}
echo "base:$base\n";
echo "now:".strftime('%Y-%m-%d %H:%M:%S')."\n\n";
}
結果はこんな感じ
timezone:UCT
4: 11/05 00:00
5: 11/06 00:00
6: 11/07 00:00
7: 11/08 00:00
base:1320105600
now:2011-11-08 23:50:43 
timezone:Etc/GMT-9
4: 11/05 00:00
5: 11/06 00:00
6: 11/07 00:00
7: 11/08 00:00
base:1320073200
now:2011-11-09 08:50:43 
timezone:Asia/Tokyo
4: 11/05 00:00
5: 11/06 00:00
6: 11/06 23:00
7: 11/07 23:00
base:1320120000
now:2011-11-08 18:50:43 
timezone:America/New_York
4: 11/05 00:00
5: 11/06 00:00
6: 11/06 23:00
7: 11/07 23:00
base:1320120000 
now:2011-11-08 18:50:43
そうそう、 日本は震災でアメリカに..そんなわけない。
使っているサーバのタイムゾーンのデータが壊れているようだ。

ローカルのphp5.3.3の環境では、timezone:Asia/Tokyoの表示は
timezone:Etc/GMT-9と同じ結果になっている。
不思議な動作をするサーバはphp5.3.1。
業務で使うサーバもほぼ同じ環境だから確認しておかなくては。

2011年9月8日木曜日

mySQLの CASE WHENはSQLが長くなる

mySQLの CASE WHENはSQLが長くなるので、短く書く方法を探ってみる。

mySQLのマニュアル比較演算子の冒頭に
「比較演算は、1(TRUE)、0(FALSE)、または NULL の値を返します。」
と書かれている。

なので、下記4つのSQLはすべて同じ結果になる。(はずw。ただし列Cは数値型だとする)

SELECT CASE WHEN `a`=`b` THEN `c` ELSE 0 END FROM `abc`;
SELECT CASE `a` WHEN `b` THEN `c` ELSE 0 END FROM `abc`;
SELECT IF(`a`=`b`,`c`,0) FROM `abc`;
SELECT (`a`=`b`)*`c` FROM `abc`

お好みはどれでしょう。