PHPのarray_shiftにおける不可解な挙動と暫定処置

スクリーンショット 2014-12-25 16.19.40
CakePHPにて、メールアドレスや、パスワードで用いられる同一チェックのロジックを以下のサイトを参照して作成してみました。
[CakePHP]よくある同一チェックを導入

※1…メールアドレス入力部(123@123.com)
※2…チェック用メールアドレス入力部(123@123.com)
※2’…2つのメールアドレス比較
※3…比較のロジック

まさに ※1 → ※2 → ※3
とシンプルに実施され、※3において
strcmp(A,B)
とA,Bが比較されるロジックです。
A,B それぞれ入力したメールアドレスがあてられます。

//### バリデーションメイン部 ###

var $validate = array(
 'mailaddress' => array(  ※1
 もろもろのルール
 )
 ),
 'mailaddress_chk' => array(  ※2
 もろもろのルール
 'sameCheck' => array(  ※2’
 'rule' => array('sameCheck', 'mailadrees'),
 もろもろのルール
 )
 )

//### 同一チェック ###

function sameCheck($data, $target) {
	return strcmp(array_shift($data), $this->data[$this->name][$target]) == 0; ※3
}

※3の続きの説明
strcmp(A,B)ですが、A=Bなら

strcmp(A,B)=0
return 0==0 ->True

になるはずなのでしょうが、どうあがいても↓ここから抜け出せない???
スクリーンショット 2014-12-25 16.17.56

A と B 比較がうまく言っていない…、A B は違う値と認識されてるのか?とまず疑い…Debugをしてみるも

Debug(array_shift($data))

表示結果 -> string(11) 123@123.com

Debug($this->data[$this->name][$target])

表示結果 -> string(11) 123@123.com

……。等しい値と認識しているようです。
まぁ当然だよね、と思い次の確認に行くわけですが、結果的に言うとここが今回もっとも不可解な部分だったわけです。

strcmp(A,B) の比較結果をデバッグすると不思議な結果が…?

Debug( strcmp(array_shift($data), $this->data[$this->name][$target]) )

結果 -11

え?
戻り値の定義はこれなんじゃないかな(;・∀・) → (訂正

0 等しい
1 文字列1 > 文字列2
-1 文字列1 < 文字列2 関数の戻り値

最初はこのstrcmpを疑っていたのですが、そもそもstrcmpに頼らずif文で代替すればよいわけで…が、結局、それでも A=B とは認めてくれないのです。
つまり、strcmpの-11が仕様かどうかは置いておくとして、原因はA,Bそのものの値が問題のようです。

そこで、浅はかなやり方なんですけどこんな風に直打ちしてみました。

Debug( strcmp("123@123.com", $this->data[$this->name][$target]) )

結果 0 → 正常

Debug( strcmp(array_shift($data), "123@123.com" )

結果 -11 → 異常

これで犯人が特定されますた!
何でこの様になるのかはわからないけどね。
A にあたる array_shift($data) は姿・形が同じように見えるが、似て異なる実は得体のしれない存在だということ。

そこでひらめいたのですが、表面上おなじに見えるのだから、

function sameCheck($data, $target){
 $foo = (string)array_shift($data);
 return strcmp($foo,$this->data[$this->name][$target]) == 0;
}

予め正しい型の箱を準備して、怪しい array_shift($data) を強引にキャストしてしまえ!
結果、正常な挙動になりました。

あまりにも奇妙すぎて特定に時間がかかりました。
しかしながら、根本問題が解決していないため追加情報がある方がいましたら是非お待ちしています。

関連してそうなエントリ

koda