下記のようなスクリプトがあります。(一例です)
----------------------------------------------
function test() {
$a = 1;
return $a;
}
if (!$b = test()) {
print "false";
}
----------------------------------------------
この時、return $a;の直前で$aの値を表示すると
値は1と表示されるのに、if文ではfalseと判定されます。
これは100%では無く、1%ぐらいの確率で起きます。
発生条件がわからないのですが、
何かわかる方はいらっしゃいますでしょうか?
質問の意味が「ユーザー定義関数を100個作ると、その中の1つくらいがfalseになる」という意味にも取れたので、静観しておりました(コメント・トラックバックを表示するにチェックが入っていればコメントできたのですけどね)
(1)原因の推定
「1つのユーザー定義関数が100回に1回くらいの割合でfalseになる」ということであれば、原因としてはMySQL関数が「構文エラーや接続失敗、SQLを実行した結果として行が存在しない場合など様々な場面でfalseを返す」ことが考えられ、結果として下記と等価の状態になっているのだと思われます
(どのような状態でfalseを返すかはマニュアル http://www.php.net/manual/ja/ref.mysql.php 参照)
<?php function test() { return false; } if (!$b = test()) { print "false"; }
(2)対策
対策としては、MySQL関数それぞれの結果に対してfalseでないかどうかを逐一確認するようにプログラムを作るということになります
手前味噌ですが、私の最近の回答から…
http://q.hatena.ne.jp/1301754362#a1065616
(データベースに接続できないというくらい重症な事象はor dieでphpの実行を止めて、結果が望みどおりでない場合は状況に応じて結果表示を変えるという形にしています)
関数化するのであればyotacaさんのおっしゃるとおり「あらかじめ何らかの値をセットしておく」といったような対策もあわせて行っておくと関数の使い勝手も向上し、ブラックボックス化することも可能になったりします(ブラックボックス化は諸刃の剣になってしまう場合もあるので注意)
if (!$b = test()) {
これは
if (!$b == test()) {
が正しいと思います
PHP Notice: Undefined variable: b・・・
とNoticeが出ます。
($bは定義されていないので当然ですが)
if (!$b = test()) {
print "false";
}
ここのIF文を
if (!$b == test()) {
または
if ($b != test()) {
としてください。
どちらのケースも
PHP Notice: Undefined variable: b・・・
とNoticeが出ます。
($bは定義されていないので当然ですが)
自信がないので、外している場合ポイントはいりません。
このifの判定は$bがブランクか否かの判定ですよね。
判定式の中で、test()の返りを代入しているので、
必ず1になると思いますが、
動作環境の問題(負荷が大きくて値を取得できないなど?)で、
functionからの返りを取得できない場合にfalseになるのではないでしょうか?
私なら、用心して、あらかじめ$bに代入してからifの判定します。
下記の様な感じだとどうなりますか?
function test() {
$a = 1;
return $a;
}
$b = test();
if (!$b) {
print "false";
}
そうですね。実際はtest()の中ではいろいろやって、
その返り値がfalseなら○○の処理をする
という事を想定して作っています。
最終的には私も、予め代入してから判定するようにして、
問題無く動作する事は確認しました。
負荷に関しては私一人で使っているサーバなので、特に高いという事はないです。
> functionからの返りを取得できない場合にfalseになるのではないでしょうか?
まさにこの部分で、そういうケースがあり得るのか?
あり得るならどういった条件で起こるのか?
といった事が知りたくて質問させて頂きました。
ご回答ありがとうございます。
PHPはシングルスレッド処理のシステムなので、ご質問のスクリプトが false を示すことは絶対に起こり得ません。
しかし、問題になっているスクリプトはご質問のような単純なものでは無いでしょうし、その中でstream_selectのような非同期処理を可能にする仕組みを導入しているとしたら、可能性として false が表示されることがあり得ます。
実際に関数の中で行っている事は、
mysql_query関数を使ってDBからデータを取得し、
その結果を返すようにしております。
ご指摘の通り、非同期処理ならあり得る気もしますが、
returnの直前の出力では値があるのに、
その後のif文でfalseになる事は無い気がします。
(当然出力される順番も正常です)
ご回答ありがとうございます。
質問の意味が「ユーザー定義関数を100個作ると、その中の1つくらいがfalseになる」という意味にも取れたので、静観しておりました(コメント・トラックバックを表示するにチェックが入っていればコメントできたのですけどね)
(1)原因の推定
「1つのユーザー定義関数が100回に1回くらいの割合でfalseになる」ということであれば、原因としてはMySQL関数が「構文エラーや接続失敗、SQLを実行した結果として行が存在しない場合など様々な場面でfalseを返す」ことが考えられ、結果として下記と等価の状態になっているのだと思われます
(どのような状態でfalseを返すかはマニュアル http://www.php.net/manual/ja/ref.mysql.php 参照)
<?php function test() { return false; } if (!$b = test()) { print "false"; }
(2)対策
対策としては、MySQL関数それぞれの結果に対してfalseでないかどうかを逐一確認するようにプログラムを作るということになります
手前味噌ですが、私の最近の回答から…
http://q.hatena.ne.jp/1301754362#a1065616
(データベースに接続できないというくらい重症な事象はor dieでphpの実行を止めて、結果が望みどおりでない場合は状況に応じて結果表示を変えるという形にしています)
関数化するのであればyotacaさんのおっしゃるとおり「あらかじめ何らかの値をセットしておく」といったような対策もあわせて行っておくと関数の使い勝手も向上し、ブラックボックス化することも可能になったりします(ブラックボックス化は諸刃の剣になってしまう場合もあるので注意)
かなり簡略化して例を書いてしまい申し訳ございません。
実際にはMySQLからの戻りをきちんとチェックし、
値が入っている事を確認した上でreturnしています。
まさしくwindofjuly様の回答のような形でチェックしています。
そのreturn直前にvar_dumpして値が入っている事を確認しました。
しかし、その関数の戻りがfalseになってしまうという話でした。
ご回答ありがとうございます。
的外れな感じがしますが一応回答します。
http://www.workspot.jp/tech/php_tips2.php
test()が0を返すのと、falseを返すのは同じだというのは大丈夫ですよね?
>そのreturn直前にvar_dumpして値が入っている事を確認しました。
>しかし、その関数の戻りがfalseになってしまうという話でした。
falseだと判断される場合のretuen直前のvar_dumpの値を調べてみれば
何か規則が見つかると思います。
0とfalseについては大丈夫です。
> falseだと判断される場合のretuen直前のvar_dumpの値を調べてみれば
> 何か規則が見つかると思います。
全く同じ値なのに、1%ぐらいの確率でfalseになります。
作成した関数はDBにトラブルが無い限りは同じ値を返すようになっています。
当然、問題無くデータを取得して返却している事は確認しています。
ご回答ありがとうございます。
原因の切り分けがこのままではできませんので問題を特定できません。
function test() {
$a = 1;
return $a;
}
if (!$b = test()) {
print "false";
}
1%という高い確率でおこるのでこのような簡単なサンプルを作成して
100万回ぐらい実行してみてはどうでしょうか?
100回に1回も起こるような現象の原因が特定できないことは普通あり得ません。
問題が発生したその時に
retuenの値は正常なのにfalseとして処理されるということで間違いはないでしょうか?
問題のない時に確認したとか理論上はそうだとかは意味がありませんのではっきり区別
していかないと原因が特定できません。
function test() {
$a = 1;
return $a;
}
$b = test();
if (!$b) {
print "false";
}
に書き換えることは問題ないと思いますのでこれでも1%の確率でおこるのかを
まず調査すべきだと思います。これで起きると起きないのでは大きく原因が違うと思います。
理論上あり得ないケースであっても1つずつ消していかない限り原因を絞り込めません。
理論上は結果は同じはずだからということで実証をしないとか、1ケースだけ確認して正しいと
認識してるからわからないのでは?
まさしくwindofjuly様の回答のような形でチェックしています。
そのreturn直前にvar_dumpして値が入っている事を確認しました。
しかし、その関数の戻りがfalseになってしまうという話でした。
これで再現させた時はvar_dumpの値はおかしくなかったと言えるのならはっきりそう回答願います。
調査手法に問題があるのでは?そういえないのなら、値が入ってるとかいう回答に意味はありません。
問題が有る場合、無い場合どちらでもreturn直前は正常に値が入っています。
提示して頂いた方法では問題は起きません。
> これで再現させた時はvar_dumpの値はおかしくなかったと言えるのならはっきりそう回答願います。
> 調査手法に問題があるのでは?そういえないのなら、値が入ってるとかいう回答に意味はありません。
文章の意味が理解できないので回答を控えさせていただきます。
かなり簡略化して例を書いてしまい申し訳ございません。
実際にはMySQLからの戻りをきちんとチェックし、
値が入っている事を確認した上でreturnしています。
まさしくwindofjuly様の回答のような形でチェックしています。
そのreturn直前にvar_dumpして値が入っている事を確認しました。
しかし、その関数の戻りがfalseになってしまうという話でした。
ご回答ありがとうございます。