Archive

Posts Tagged ‘specific’

変数の評価

これは気づかないとかなりハマるし、アプリにバグを埋め込むことになります。

フォームから来た変数で 0 を値に持つ変数を空文字列かどうか評価したら空として認識してる気がしたのでテストコードを書いてみました。

以下のコードを実行

$i = 0;
print_r(’$i: ‘ . $i . “\n”);
print_r(’$i == null: ‘ . ($i == null) . “\n”);
print_r(’$i == false: ‘ . ($i == false) . “\n”);
print_r(’$i == “”: ‘ . ($i == “”) . “\n”);

以下が結果

$i: 0
$i == null: 1
$i == false: 1
$i == “”: 1

null の評価については今更何も言うまい。
確かに空文字列か評価したら true を返しています。0 という値が入ってるのに。最初に $i を integer として定義してるので型変換が起きてるのだろうと思って、型キャストして評価してみました。

コード

print_r(’(string) $i == “”: ‘ . ((string) $i == “”) . “\n”);

結果

(string) $i == “”:

一応期待した動作になりましたが Perl に慣れていると気持ち悪いです。
慣れるべきなのかも知れませんが、明らかに文字列として評価を試みてるのだから、そこでも型の自動変換をして欲しいものです。

今回は、フォームから来た時点では string でしたが、-= で減算処理をしていたため、その時点で integer に自動変換され、文字列的には空でないのに、”" オペランドを integer として評価したために、0 == “” が true になったもののと思われます。

自動型変換の演算子とオペランドの関係については、下記参照。
http://jp.php.net/manual/ja/language.types.type-juggling.php

常に厳密比較を使った方が楽かも知れません。
http://jp.php.net/manual/ja/types.comparisons.php

PHP 配列の振る舞い

色々テストしてみました。

#####
print_r($a);
—->
(出力なし)

#####
$a = array();
print_r($a);
—–>
Array ( )

#####
print_r(count($a));
—->
0

#####
$a = array();
print_r(count($a));
—->
0

一応、前もって $a = array(); と配列型を宣言しておけば、

if (count($a)) {

としても PHP Notice も出ない。
is_array() だと宣言してないと Notice 出る。
isset() だと宣言していなくても Notice 出ないが、配列が空でも true が返るので意図したこととは違うでしょう。

ビット列型の挙動

CREATE TABLE するときに

foo BIT VARYING(8)
と、しても、

SELECT * FROM t WHERE B'00010000' = foo & B'00010000';
と、すると、

ERROR: cannot AND bit strings of different sizes
などと言われてしまう。

SELECT * FROM t WHERE B'00010000' = foo::bit & B'00010000'::bit;
などとしても同じ。

マニュアルのビット文字列関数と演算子を見てみたら、

単に”bit”にキャストすることは bit(1)にキャストすることを意味することに注意
してください。つまり、単に整数の最下位ビットのみが伝播されることになります。

なんて書いてある。

SELECT * FROM t WHERE B'00010000' = foo::bit(8) & B'00010000'::bit(8);
と、したら、意図するように動いてくれました。

しかし、CREATE TABLE する時に、ビット列データ型ってことも分かっていることだし、桁数だって分かってると思う。文字列で入力しても桁数揃えているんだから、ちゃんと解析して欲しいものです。

しかし、ビット列を主キーにしているテーブルでは、

SELECT * FROM t WHERE foo = foo & b'000100100000';
としても意図する通りに動きました。この差は謎のまま。

比較演算子の困った仕様

以前から分かってたことなのですが、比較演算子の仕様がかなり不便です。何が不便かっていうと、0 と null の扱い。

$v = 0 で
$v == null が true

$v = null で
$v == 0 も true

なので、

同じ $v = 0 でも、
if ($v == 0) {
} elseif ($v == null) {
}

と、

if ($v == null) {
} elseif ($v == 0) {
}

で結果が違ったりする。勿論 Smarty の {if,elseif,else} 関数でも一緒。

結局、思った通りに動作させるには、PHP4 以上という縛りで、
$v === 0 と、型までチェックするようにするしかない。

しかし、Smarty の {if,elseif,else} は、=== 演算子をサポートしていないので、結局 $v == 0 より $v == null を先に評価させるしかない。