web-dev-qa-db-ja.com

PHPで変数の存在をテストする最良の方法。 isset()は明らかに壊れています

isset() docs から:

isset() will return FALSE if testing a variable that has been set to NULL.

基本的に、isset()は変数が設定されているかどうかをチェックしませんが、変数がNULL以外に設定されているかどうかをチェックします。

それを考えると、変数の存在を実際にチェックする最良の方法は何ですか?私は次のようなものを試しました:

if(isset($v) || @is_null($v))

@は、$vが設定されていない場合の警告を回避するために必要です)が、is_null()にはisset()と同様の問題があります。未設定変数でTRUEを返します。また、次のようにも見えます。

@($v === NULL)

@is_null($v)とまったく同じように機能するので、それもありません。

PHPの変数の存在を確実に確認するにはどうすればよいですか?


編集:PHPには、設定されていない変数とNULLに設定されている変数の間に明確な違いがあります。

<?php
$a = array('b' => NULL);
var_dump($a);

PHPは、$a['b']が存在し、NULL値を持っていることを示しています。追加する場合:

var_dump(isset($a['b']));
var_dump(isset($a['c']));

isset()関数で私が話しているあいまいさがわかります。これら3つのvar_dump()sのすべての出力を次に示します。

array(1) {
  ["b"]=>
  NULL
}
bool(false)
bool(false)

さらに編集:2つのこと。

1つ、ユースケース。 SQL UPDATEステートメントのデータに変換される配列。配列のキーはテーブルの列で、配列の値は各列に適用される値です。テーブルの列は、NULL値を保持できます。これは、配列でNULL値を渡すことで示されます。 need存在しない配列キーと、NULLに設定されている配列の値を区別する方法。これは、列の値を更新しないことと、列の値をNULLに更新することの違いです。

第二に、 Zoredacheの答えarray_key_exists()は、上記のユースケースおよびグローバル変数に対して正しく機能します。

<?php
$a = NULL;
var_dump(array_key_exists('a', $GLOBALS));
var_dump(array_key_exists('b', $GLOBALS));

出力:

bool(true)
bool(false)

ほぼすべての場所で適切に処理されるため、存在しない変数とNULLに設定されている変数との間にあいまいさがあることがわかります。私はarray_key_exists()をPHPは、変数の存在を本当にチェックします

(私が考えることができる他のケースのみがクラスプロパティであり、そのためにproperty_exists()があり、 its docs によれば、array_key_exists()と同様に機能し、設定されていないこととNULLに適切に区別されます)

184
chazomaticus

チェックしている変数がグローバルスコープにある場合は、次のようにします。

array_key_exists('v', $GLOBALS) 
95
Zoredache

さまざまな議論と回答の概要を説明しよう:

issetを使用できるすべての方法を置き換えることができる質問への単一の答えはありません。コードゴルフを超えた疑わしい価値。他のユースケースは、「壊れた」または「一貫性のない」ものではなく、issetに対するnullの反応が論理的な振る舞いである理由を示しています。

実際の使用例(ソリューション付き)

1.配列キー

配列は変数のコレクションのように扱うことができ、unsetおよびissetはそれらをあたかもそれらのように扱います。ただし、それらは反復、カウントなどが可能であるため、欠損値は値がnullであるものと同じではありません。

この場合の答えは、array_key_exists()の代わりに isset() を使用することです。

これは配列を関数の引数としてチェックするため、配列自体が存在しない場合、PHPは引き続き「通知」を発行します。場合によっては、各ディメンションを最初に初期化する必要があると正当に主張できるため、通知がその役割を果たしています。その他の場合、配列の各次元を順番にチェックする「再帰的な」array_key_exists関数はこれを回避しますが、基本的には@array_key_existsと同じです。また、null値の処理に対してやや接線方向です。

2.オブジェクトのプロパティ

「オブジェクト指向プログラミング」の伝統的な理論では、カプセル化とポリモーフィズムはオブジェクトの重要な特性です。 PHPのようなクラスベースのOOP実装では、カプセル化されたプロパティはクラス定義の一部として宣言され、アクセスレベル(publicprotected、またはprivate)が与えられます。

ただし、PHPでは、配列のキーのように、オブジェクトにプロパティを動的に追加することもできます。また、クラスレスオブジェクト(技術的には、メソッドを持たない組み込みのstdClassのインスタンスを使用する人もいます)またはプライベート機能)連想配列と同様の方法で。これにより、特定のプロパティが与えられたオブジェクトに追加されているかどうかを関数が知りたい場合があります。

配列キーと同様に、オブジェクトプロパティをチェックするためのソリューションが言語に含まれており、合理的には、 property_existsと呼ばれます。

議論の余地のないユースケース

3. register_globals、およびその他のグローバル名前空間の汚染

register_globals機能は、HTTPリクエストの側面(GETおよびPOST_パラメーター、およびCookie)によって名前が決定されるグローバルスコープに変数を追加しました。これにより、バグのある安全でないコードが発生する可能性があります。このため、 PHP 4.2、2000年8月リリース 以降デフォルトで無効になり、 PHP 5.4、2012年3月リリース で完全に削除されました。ただし、一部のシステムは、この機能が有効またはエミュレートされた状態で実行されている可能性があります。 globalキーワードまたは$GLOBALS配列を使用して、他の方法でグローバル名前空間を「汚染」することもできます。

まず、GET、POST、およびCookieの値は常に文字列になり(register_globalsnullからtrueを返すため)、''自体が予期せずisset変数を生成する可能性は低く、セッションの変数は完全にプログラマーの制御下にある必要があります。

第二に、値nullを持つ変数の汚染は、これが以前の初期化を上書きする場合にのみ問題になります。 nullで初期化されていない変数を「上書き」することは、コードが2つの状態を区別している場合にのみ問題となるため、この可能性はそれ自体が引数againstであり、区別。

4. get_defined_varsおよびcompact

get_defined_varscompact など、PHPでほとんど使用されない関数を使用すると、変数名を配列のキーであるかのように扱うことができます。グローバル変数の場合、 スーパーグローバル配列$GLOBALS は同様のアクセスを許可し、より一般的です。関連するスコープで変数が定義されていない場合、これらのアクセス方法は異なる動作をします。

これらのメカニズムのいずれかを使用して変数のセットを配列として扱うことにした後は、通常の配列と同じ操作をすべて行うことができます。したがって、1を参照してください。

これらの関数の動作を予測するためだけに存在する機能(たとえば、「get_defined_varsによって返される配列にキー 'foo'がありますか?」)は、単に関数を実行し、悪影響なしで見つけることができるため、不要です。 。

4a。変数変数($$foo

変数のセットを連想配列に変換する関数とはまったく同じではありませんが、ほとんどの場合、 "変数変数" ( "この他の変数に基づいて命名された変数に割り当てる")を使用できます。代わりに連想配列を使用するように変更されました。

基本的に、変数名はプログラマーによって値に与えられるラベルです。実行時に決定する場合、それは実際にはラベルではなく、キーバリューストアのキーです。より実際的には、配列を使用しないことにより、カウント、反復などの機能を失います。変数が$$fooによって上書きされる可能性があるため、変数をキー値ストアの「外部」に置くことも不可能になる可能性があります。

連想配列を使用するように変更すると、コードはソリューション1の影響を受けやすくなります。間接オブジェクトプロパティアクセス(例:$foo->$property_name)は、ソリューション2で対処できます。

5. issetは、array_key_existsよりも入力がはるかに簡単です。

これが本当に関連しているのかはわかりませんが、はい、PHPの関数名はかなり長くなり、時々矛盾す​​ることがあります。どうやら、PHPの先史時代のバージョンはハッシュキーとして関数名の長さを使用していたため、Rasmusは意図的にhtmlspecialcharsのような関数名を作成し、異常な数の文字を持つようにしました...

それでも、少なくともJavaを書いているわけではありませんよね? ;)

6.初期化されていない変数には型があります

変数の基本に関するマニュアルページ には次のステートメントが含まれています。

初期化されていない変数には、使用されるコンテキストに応じたタイプのデフォルト値があります

Zend Engineに「初期化されていないが既知のタイプ」という概念があるかどうか、またはこれがステートメントを読みすぎているかどうかはわかりません。

明らかなのは、そのページで初期化されていない変数について説明されている動作は、値がnullである変数の動作と同じであるため、動作に実質的な違いはないということです。 1つの例を選ぶと、このコードの$a$bの両方が整数42になります。

unset($a);
$a += 42;

$b = null;
$b += 42;

(最初のコードは、より良いコードを作成するために、宣言されていない変数に関する通知を出しますが、実際のコードの実行方法に違いはありません。)

99.関数が実行されたかどうかの検出

(他のものよりもずっと長いので、これを最後に保ちます。多分後で編集します...)

次のコードを検討してください。

$test_value = 'hello';
foreach ( $list_of_things as $thing ) {
    if ( some_test($thing, $test_value) ) {
        $result = some_function($thing);
    }
}
if ( isset($result) ) {
    echo 'The test passed at least once!';
}

some_functionnullを返すことができる場合、some_testechoを返したにもかかわらず、trueに到達しない可能性があります。プログラマの意図は、$resultが設定されたことがないことを検出することでしたが、PHPでは設定できません。

ただし、このアプローチには他の問題もあり、外側のループを追加すると明らかになります。

foreach ( $list_of_tests as $test_value ) {
    // something's missing here...
    foreach ( $list_of_things as $thing ) {
        if ( some_test($thing, $test_value) ) {
            $result = some_function($thing);
        }
    }
    if ( isset($result) ) {
        echo 'The test passed at least once!';
    }
}

$resultは決して明示的に初期化されないため、最初のテストに合格すると値を取得し、後続のテストに合格したかどうかを判断できなくなります。 これは、変数が適切に初期化されない場合、実際には非常に一般的なバグです。

これを修正するには、何かが足りないとコメントした行で何かをする必要があります。最も明らかな解決策は、$resultを返さない「端末値」にsome_functionを設定することです。これがnullの場合、残りのコードは正常に機能します。 some_functionが非常に予測不可能な戻り値型(おそらくそれ自体が悪い兆候)を持っているために端末値の自然な候補がない場合、追加のブール値、例えば代わりに$foundを使用できます。

思考実験1:very_null定数

PHPは理論的には、nullと同様に、ここで端末値として使用するための特別な定数を提供できます。おそらく、関数からこれを返すことは違法であるか、nullに強制され、関数引数として渡す場合も同じことが当てはまります。これにより、この非常に特殊なケースはわずかに単純になりますが、コードをリファクタリングすることを決定するとすぐに(たとえば、内側のループを別の関数に入れると)役に立たなくなります。関数間で定数を渡すことができた場合、some_functionが定数を返さないことを保証できなかったため、ユニバーサル端末値としては有用ではなくなりました。

この場合、初期化されていない変数を検出するための引数は、その特別な定数の引数に要約されます。コメントをunset($result)で置き換え、$result = nullとは異なる扱いをすると、$resultの「値」を導入できます。特定の組み込み関数によってのみ検出できます。

思考実験2:割り当てカウンター

最後のifが何を求めているかを考えるもう1つの方法は、「何かが$resultに割り当てられましたか?」です。 $resultの特別な値であると考えるのではなく、Perlの「変数汚染」に少し似た、変数の「メタデータ」aboutと考えることができます。そのため、issetではなくhas_been_assigned_toを呼び出し、unsetではなくreset_assignment_stateを呼び出します。

しかし、そうであれば、なぜブール値で停止するのですか?テストに合格した回数回数を知りたい場合はどうしますか。メタデータを整数に拡張し、get_assignment_countreset_assignment_countを使用するだけです...

明らかに、このような機能を追加すると、言語の複雑さとパフォーマンスのトレードオフが生じるため、予想される有用性と慎重に比較検討する必要があります。 very_null定数と同様に、非常に狭い状況でのみ有用であり、同様にリファクタリングに対して耐性があります。

うまくいけば明白な質問は、PHPランタイムエンジンが、通常のコードを使用して明示的に行うのではなく、そのようなことを追跡することを事前に想定する理由です。

44
IMSoP

特定の状況でどの比較演算を使用するかを理解しようとして、少し迷子になることがあります。 isset()は、初期化されていない値または明示的にnull値にのみ適用されます。 nullを渡す/割り当てることは、論理比較が期待どおりに機能することを保証する優れた方法です。

それでも、考えるのは少し難しいので、異なる操作によって異なる値がどのように評価されるかを比較する簡単なマトリックスを次に示します。

|           | ===null | is_null | isset | empty | if/else | ternary | count>0 |
| -----     | -----   | -----   | ----- | ----- | -----   | -----   | -----   |
| $a;       | true    | true    |       | true  |         |         |         |
| null      | true    | true    |       | true  |         |         |         |
| []        |         |         | true  | true  |         |         |         |
| 0         |         |         | true  | true  |         |         | true    |
| ""        |         |         | true  | true  |         |         | true    |
| 1         |         |         | true  |       | true    | true    | true    |
| -1        |         |         | true  |       | true    | true    | true    |
| " "       |         |         | true  |       | true    | true    | true    |
| "str"     |         |         | true  |       | true    | true    | true    |
| [0,1]     |         |         | true  |       | true    | true    | true    |
| new Class |         |         | true  |       | true    | true    | true    |

テーブルに合わせるために、ラベルを少し圧縮しました。

  • $a;は、宣言されているが割り当てられていない変数を参照します
  • 最初の列の他のすべては、次のような割り当てられた値を参照します。
    • $a = null;
    • $a = [];
    • $a = 0;
  • 列は、次のような比較演算を参照します。
    • $a === null
    • isset($a)
    • empty($a)
    • $a ? true : false

結果はすべてブール値であり、trueが出力され、falseは省略されます。

テストは自分で実行できます。この要点を確認してください。
https://Gist.github.com/mfdj/8165967

20
Mark Fox

コンパクトな言語構成を使用して、null変数の存在をテストできます。存在しない変数は結果に表示されませんが、null値が表示されます。

$x = null;
$y = 'y';

$r = compact('x', 'y', 'z');
print_r($r);

// Output:
// Array ( 
//  [x] => 
//  [y] => y 
// ) 

あなたの例の場合:

if (compact('v')) {
   // True if $v exists, even when null. 
   // False on var $v; without assignment and when $v does not exist.
}

もちろん、グローバルスコープの変数の場合、array_key_exists()も使用できます。

B.t.w.個人的には、存在しない変数とヌル値を持つ変数との間に意味の違いがあるペストのような状況を避けます。 PHPおよび他のほとんどの言語は、存在するとは考えていません。

17
Matijs

NULLの説明、論理的に考える

これに対する明白な答えは...変数をNULLとして初期化せず、それらが意図したものに関連するものとして初期化することだと思います。

NULLを適切に扱う

NULLは、「存在しない値」として扱う必要があります。これは、NULLの意味です。変数は、PHPに存在するものとして分類することはできません。これは、変数がどのタイプのエンティティになろうとしているのかが通知されていないためです。存在しない可能性もあるので、PHPは「いい、それはとにかく意味がなく、NULLがこれを言う私の方法だからではない」と言うだけです。

引数

今議論しましょう。 「しかし、NULLは0またはFALSEまたは ''と言っているようなものです。

間違った0-FALSE- ''はすべて空の値として分類されますが、何らかのタイプの値または質問に対する事前に決められた回答として指定されています。 FALSEはyesまたはnoに対する回答、''は誰かが提出したタイトルへの回答、およびは数量に対する回答または時間など。それらは、設定されているものとして有効にする何らかのタイプの回答/結果として設定されます。

NULLは、これまでのところ何の答えもありません。yesまたはnoを通知せず、時間を通知せず、空の文字列が送信されたことを通知しません。これがNULLを理解するための基本的なロジックです。

概要

問題を回避するための奇抜な関数を作成することではなく、脳のNULLの見方を変えるだけです。 NULLの場合、何も設定されていないと想定します。変数を事前定義している場合は、使用する用途の種類に応じて、0、FALSE、または ""として変数を事前定義します。

これを引用してください。それは私の論理的な頭の上にあります:)

15
greatbigmassive

property_exists により、オブジェクトのプロパティの存在を確認できます。

単体テストの例:

function testPropertiesExist()
{
    $sl =& $this->system_log;
    $props = array('log_id',
                   'type',
                   'message',
                   'username',
                   'ip_address',
                   'date_added');

    foreach($props as $prop) {
        $this->assertTrue(property_exists($sl, $prop),
                           "Property <{$prop}> exists");
    }
}
9
Thomas

NULLの意味に関するgreatbigmassiveの説明 に追加するものとして、「変数の存在」が実際に意味することを考慮してください。

多くの言語では、使用する前にすべての変数を明示的に宣言する必要があります;これにより、そのタイプが決定される場合がありますが、さらに重要なのは、そのscopeを宣言することです。変数は、そのスコープ内のどこにでも「存在」し、その外側には存在しません-関数全体、または単一の「ブロック」です。

スコープ内で、変数は、プログラマーが選択したラベルに何らかの意味を割り当てます。そのラベルの範囲外では、そのラベルは無意味です(別のスコープで同じラベルを使用するかどうかは基本的に無関係です)。

PHPでは、変数を宣言する必要はありません-必要なときにすぐに有効になります。初めて変数に書き込むとき、PHPはその変数のエントリをメモリに割り当てます。現在エントリを持たない変数から読み取る場合、PHPはその変数の値がNULLであると見なします。

ただし、変数を最初に「初期化」せずに使用すると、一般に自動コード品質検出器は警告を表示します。まず、これは$thingIdに割り当てるが$thing_idから読み取るなど、タイプミスを検出するのに役立ちます。しかし、第二に、宣言と同様に、その変数が意味を持つ範囲を考慮することを強制します。

変数が「存在する」かどうかを気にするコードは、その変数のスコープの一部です-初期化されているかどうかにかかわらず、あなたはプログラマとして持っていますコードのその時点でのラベルの意味を考えます。あなたはそれを使用しているので、ある意味で「存在する」必要があり、存在する場合は暗黙的な値を持たなければなりません。 PHPでは、その暗黙的な値はnullです。

PHPの動作方法により、既存の変数のネームスペースを、意味を与えたラベルのスコープとしてではなく、何らかのキー値ストアとして扱うコードを書くことができます。たとえば、$var = $_GET['var_name']; $$var = $_GET['var_value'];のようなコードを実行できます。 できるからといって、それが良いアイデアだというわけではありません。

PHPには、連想配列と呼ばれる、キーと値のストアを表現するはるかに優れた方法があります。また、配列の値は変数のように扱うことができますが、配列全体に対して操作を実行することもできます。 連想配列がある場合は、 array_key_exists()を使用してキーが含まれているかどうかをテストできます

オブジェクトを同様の方法で使用して、プロパティを動的に設定することもできます。その場合、 property_exists() をまったく同じ方法で使用できます。もちろん、クラスを定義する場合、そのプロパティを宣言できます-publicprivateprotectedスコープから選択することもできます。

初期化されていない(または明示的にunset()である)変数と(配列キーやオブジェクトプロパティではなく)変数の間にtechnicalの違いがありますがその値がnullである場合、その違いをmeanfulと見なすコードは、使用するつもりのない方法で変数を使用しています。

4
IMSoP

isset は、変数が設定されているかどうかをチェックし、設定されている場合は、そのvalueがNULLでないかどうかをチェックします。後者は(私の意見では)この機能の範囲内ではありません。変数がNULLであるかが設定されていないか、または明示的に設定されているためかを判断する適切な回避策はありませんNULL.

考えられる解決策の1つを次に示します。

$e1 = error_get_last();
$isNULL = is_null(@$x);
$e2 = error_get_last();
$isNOTSET = $e1 != $e2;
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0

他の回避策は get_defined_vars() の出力をプローブすることです:

$vars = get_defined_vars();
$isNOTSET = !array_key_exists("x", $vars);
$isNULL = $isNOTSET ? true : is_null($x);
echo sprintf("isNOTSET: %d, isNULL: %d", $isNOTSET, $isNULL);

// Sample output:
// when $x is not set: isNOTSET: 1, isNULL: 1
// when $x = NULL:     isNOTSET: 0, isNULL: 1
// when $x = false:    isNOTSET: 0, isNULL: 0
3
Salman A

これに2セントを簡単に追加します。この問題が紛らわしい理由の1つは、このシナリオがエラーレポートnotで同じ結果を返すように見えるためです:

$a = null;
var_dump($a); // NULL
var_dump($b); // NULL

この結果から、$a = nullを定義することと$bをまったく定義しないこととの違いは何もないと仮定できます。

クランクエラーの報告:

NULL

Notice: Undefined variable: b in xxx on line n
NULL

注:未定義変数エラーをスローしましたが、var_dumpの出力値はNULLのままです。

PHPには、null変数と未定義の変数を区別する内部機能があります。私には、これをチェックするための組み込み関数があるべきだと思われます。

受け入れられた答えはほとんどの部分で良いと思いますが、もしそれを実装しようと思ったら、そのラッパーを書きます。前述のように この回答では 、これが問題であった状況に実際に遭遇していないことに同意する必要があります。私はほとんどの場合、変数が設定および定義されているか、または定義されていない(未定義、未設定、null、空白など)シナリオに陥っているようです。このような状況が将来発生しないとは言いませんが、それは非常にユニークな問題であると思われるので、PHP開発者がこれを入れようとしていなかったことに驚かないです。

2
Robbie Averill

NULLについてのあなたの推論に同意しません、そして、NULLについてのあなたの考え方を変える必要があると言うのはただ奇妙です。

Isset()は正しく設計されていなかったと思います。isset()は変数が設定されているかどうかを通知し、変数の実際の値に関係するべきではありません。

データベースから返された値をチェックしていて、列の1つにNULL値がある場合、値がNULLでも存在するかどうかを知りたい場合は... nope dont trust isset()here。

同様に

$a = array ('test' => 1, 'hello' => NULL);

var_dump(isset($a['test']));   // TRUE
var_dump(isset($a['foo']));    // FALSE
var_dump(isset($a['hello']));  // FALSE

isset()は次のように動作するように設計されている必要があります。

if(isset($var) && $var===NULL){....

このように、型をチェックするのはプログラマに任せ、isset()に任せて、値がNULLであるために存在しないと仮定するのではなく、ただの愚かな設計

2

次を実行した場合:

echo '<?php echo $foo; ?>' | php

エラーが発生します:

PHP Notice:  Undefined variable: foo in /home/altern8/- on line 1

次を実行した場合:

echo '<?php if ( isset($foo) ) { echo $foo; } ?>' | php

エラーは発生しません。

設定する必要がある変数がある場合、通常は次のようなことを行います。

$foo = isset($foo) ? $foo : null;

または

if ( ! isset($foo) ) $foo = null;

そうすれば、スクリプトの後半で安全に$ fooを使用でき、「設定されている」こと、およびデフォルトでnullになっていることがわかります。後で、変数がnullであっても、変数が存在することが確実に必要な場合、if ( is_null($foo) ) { /* ... */ }できます。

完全な isset documentation は、最初に貼り付けられたものだけではありません。はい、以前に設定されていたが現在はnullである変数に対してfalseを返しますが、変数がまだ設定されていない場合(未設定)および未設定としてマークされている変数に対してもfalseを返します。また、NULLバイト( "\ 0")はNULLと見なされず、trueを返すことにも注意します。

変数が設定されているかどうかを確認します。

Unset()で変数が設定解除されている場合、その変数は設定されなくなります。 NULLに設定された変数をテストする場合、isset()はFALSEを返します。また、NULLバイト( "\ 0")はPHP NULL定数と同等ではないことに注意してください。

1
Beau Simensen

使用してみてください

unset($v)

変数が設定されていないのは、特に設定されていないときだけです($ v)。 「存在」の意味はPHPの定義とは異なるようです。 NULLは確かに存在し、NULLです。

1
Joe Phillips

私は長年PHPプログラミングをしてきましたが、isset()がnull変数でfalseを返す問題に遭遇したことはありません。 OTOH、isset()がnull配列エントリで失敗する問題に遭遇しましたが、array_key_exists()はその場合に正しく動作します。

比較のために、Iconは&nullを返すように未使用の変数を明示的に定義するため、Iconのis-nullテストを使用して、未設定の変数もチェックします。これは物事を簡単にします。一方、Visual BASICには、値を持たない変数(Null、Empty、Nothingなど)に対して複数の状態があり、多くの場合、それらの状態を複数チェックする必要があります。これはバグの原因であることが知られています。

0
staticsan

私は唯一の完全な解決策は通知を報告することだと思う

error_reporting(E_ALL); // Enables E_NOTICE

ただし、未定義の変数、定数、配列キー、クラスプロパティなどによって生成されるすべての通知を修正する必要があります。これを行うと、null変数と宣言されていない変数の違いを心配する必要がなくなり、あいまいさが消えます。

通知レポートの有効化は、すべての状況で適切な代替手段とは限りませんが、有効化する正当な理由があります。

E_NOTICEエラーを修正する必要があるのはなぜですか?

私の場合、それなしでproyectで働いていましたが、変数の宣言に注意するために使用されていたので、移行は迅速でした。

0
mikl

変数が現在のスコープで定義されている($GLOBALSは信頼できない)かどうかを知る唯一の方法は、array_key_exists( 'var_name', get_defined_vars() )です。

0
Kostas Podias

Empty()関数のPHPマニュアルによれば、「変数が空であると見なされるかどうかを判断します。存在しない場合、または値がFALSEである場合、変数は空と見なされます。変数が存在しない場合は警告を生成しません。」 (私の強調。)つまり、empty()関数は、タイトルの質問ごとに、「PHPでの変数の存在をテストする最良の方法」と見なされるべきです。

ただし、empty()関数は存在し、NULLに設定されている変数にだまされる可能性があるため、これでは十分ではありません。

元の回答(比較のためにこの中断に続く)よりも面倒ではないため、以前の回答を中断してより良いものを提示します。

  function undef($dnc) //do not care what we receive
  { $inf=ob_get_contents();             //get the content of the buffer
    ob_end_clean();                     //stop buffering outputs, and empty the buffer
    if($inf>"")                         //if test associated with the call to this function had an output
    { if(false!==strpos($inf, "Undef"); //if the Word "Undefined" was part of the output
        return true;                    //tested variable is undefined
    }
    return false;                       //tested variable is not undefined
  }

次の2行のコードでは、上記の関数を使用して、変数が未定義かどうかを明らかにできます。

  ob_start();                           //pass all output messages (including errors) to a buffer
  if(undef($testvar===null))            //in this case the variable being tested is $testvar

次の例のように、これらの2行に適切なものを続けることができます。

    echo("variable is undefined");
  else
    echo("variable exists, holding some value");

関数内にob_start()と($ testvar === null)を呼び出して、変数を関数に渡すだけでしたかったのですが、機能しません。関数への変数の「参照渡し」を使用しようとしても、変数は定義済みになり、関数は以前に定義されていなかったことを検出できません。ここに示されているのは、私がやりたいことと実際に機能することの間の妥協です。

上記のことは、「未定義変数」エラーメッセージの実行を常に回避する別の方法があることを意味します。 (ここでの仮定は、そのようなメッセージを防ぐことが、変数が未定義であるかどうかをテストする理由です。)

   function inst(&$v) { return; }  //receive any variable passed by reference; instantiates the undefined

$ testvarに何かを行う前に、その関数を呼び出すだけです。

   inst($testvar);                //The function doesn't affect any value of any already-existing variable

もちろん、新しくインスタンス化された変数の値はnullに設定されます!

(中断は終了します)

それで、いくつかの勉強と実験の後、動作することが保証されているものがあります:

 function myHndlr($en, $es, $ef, $el)
 { global $er;
   $er = (substr($es, 0, 18) == "Undefined variable");
   return;
 }

 $er = false;
 if(empty($testvar))
 { set_error_handler("myHndlr");
   ($testvar === null);
   restore_error_handler();
 }
 if($er)  // will be 1 (true) if the tested variable was not defined.
 { ; //do whatever you think is appropriate to the undefined variable
 }

説明:変数$ erは、デフォルト値「エラーなし」に初期化されます。 「ハンドラー関数」が定義されています。 $ testvar(未定義かどうかを知りたい変数)が予備のempty()関数テストに合格した場合、より徹底的なテストを行います。 set_error_handler()関数を呼び出して、定義済みのハンドラー関数を使用します。次に、未定義の場合にエラーが発生する$ testvarを含む単純なID比較を実行します。ハンドラー関数はエラーをキャプチャし、エラーの理由が変数が未定義であるという事実であるかどうかを明確にテストします。結果はエラー情報変数$ erに格納されます。これは、後で$ testvarが定義されているかどうかを確認した結果として、必要な処理をテストできます。この限定された目的にのみハンドラー関数が必要なので、元のエラー処理関数を復元します。 「myHndlr」関数は一度だけ宣言する必要があります。他のコードは、$ testvarまたはこの方法でテストしたい他の変数に対して、適切な場所にコピーできます。

0