programing

PHP에서 변수의 존재를 테스트하는 가장 좋은 방법은 isset()이(가) 명확하게 끊어졌습니다.

procenter 2022. 9. 28. 22:24
반응형

PHP에서 변수의 존재를 테스트하는 가장 좋은 방법은 isset()이(가) 명확하게 끊어졌습니다.

문서에서:

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

기본적으로는isset()변수가 설정되어 있는지 여부는 전혀 체크되지 않지만, 다른 값으로 설정되어 있는지 아닌지는 체크되지 않습니다.NULL.

그렇다면 변수의 존재를 실제로 확인하는 가장 좋은 방법은 무엇일까요?나는 다음과 같이 시도했다.

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

(the)@경고를 피하기 위해 필요합니다.$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()기능.여기 이 세 가지 모든 결과물이 있습니다.var_dump()s:

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

추가 편집: 두 가지입니다.

첫째, 사용 사례.SQL의 데이터로 변환되는 어레이UPDATEstatement. 여기서 배열의 키는 테이블의 열이고 배열의 값은 각 열에 적용되는 값입니다.테이블의 모든 열은 다음 값을 포함할 수 있습니다.NULL값, 통과로 나타남NULL값을 지정합니다.존재하지 않는 어레이 키와 다음과 같이 설정된 어레이 값을 구별할 수 있는 방법이 필요합니다.NULL컬럼 값을 갱신하지 않는 것과 컬럼 값을 갱신하는 것의 차이입니다.NULL.

둘째, 조르다체의 대답입니다.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변수의 존재를 진정으로 확인하기 위해 PHP에서 가장 쉬운 공식 방법을 호출합니다.

(다른 경우로 생각할 수 있는 것은 클래스 속성뿐입니다.클래스 속성에는property_exists()이 매뉴얼에 따르면 이 매뉴얼은array_key_exists()설정되지 않은 것과 설정되지 않은 것을 적절히 구별한다는 점에서NULL.)

체크하고 있는 변수가 글로벌스코프에 포함되는 경우는, 다음의 조작을 실행할 수 있습니다.

array_key_exists('v', $GLOBALS) 

다양한 논의와 답변의 개요를 설명하려고 합니다.

모든 방법을 대체할 수 있는 유일한 답은 없습니다.일부 사용 사례는 다른 기능을 통해 해결되는 반면, 다른 사용 사례는 정밀 조사를 견디지 못하거나 코드 골프 이상의 가치를 가지고 있습니다.'고장'이나 '불일관'이 아닌 다른 사용 사례를 통해 그 이유를 알 수 있습니다.isset대한 의 반응null는 논리적인 동작입니다.

실제 사용 사례(솔루션 포함)

1. 어레이 키

어레이는 변수 집합처럼 취급할 수 있습니다.unset그리고.isset마치 그런 것처럼 대합니다.단, 이러한 값은 반복, 카운트 등이 가능하기 때문에 결측값은 다음 값이 되는 값과 같지 않습니다.null.

이 경우의 답은 가 아닌사용하는 것입니다.

이는 어레이를 함수 인수로 확인하는 것이므로 어레이 자체가 존재하지 않는 경우에도 PHP는 계속 "알림"을 발생시킵니다.경우에 따라서는 각 차원이 먼저 초기화되었어야 한다고 합리적으로 주장할 수 있기 때문에 통지가 제 기능을 하고 있다.다른 경우, "재귀적"array_key_exists배열의 각 차원을 차례로 체크하는 함수는 이를 회피하지만 기본적으로는 다음과 같습니다.@array_key_exists또, 이것은, 다음의 처리에도 어느 정도 접해 있습니다.null가치.

2. 오브젝트 속성

"개체 지향 프로그래밍"의 전통적인 이론에서 캡슐화와 다형성은 객체의 주요 속성입니다; PHP와 같은 클래스 기반 OOP 구현에서 캡슐화된 속성은 클래스 정의의 일부로 선언되며, 주어진 액세스 레벨(access levels)입니다.public,protected, 또는private).

단, PHP를 사용하면 어레이의 키처럼 오브젝트에 속성을 동적으로 추가할 수 있습니다.또한 클래스리스 오브젝트(기술적으로는 빌트인의 인스턴스)를 사용하는 사람도 있습니다.stdClass(메서드나 프라이빗 기능이 없음)를 어소시에이트 어레이와 같은 방법으로 사용합니다.이로 인해 함수가 특정 속성이 지정된 객체에 추가되었는지 여부를 확인할 수 있는 상황이 발생합니다.

어레이 키와 마찬가지로 오브젝트 속성을 체크하기 위한 솔루션이 언어에 포함되어 있습니다.이것을 합리적으로 말하면 충분합니다.

정당화될 수 없는 사용 사례(논의 포함)

3. register_globals글로벌 네임스페이스의 기타 오염

register_globalsfeature는 HTTP 요청의 측면(GET 및 POST 파라미터 및 쿠키)에 의해 이름이 결정된 글로벌스코프에 변수를 추가했습니다.이로 인해 버그가 발생하고 안전하지 않은 코드가 발생할 수 있습니다.그 때문에, PHP 4.2가 2000년 8월에 발매되어 2012년 3월에 발매된 PHP 5.4에서 완전히 삭제되어 디폴트로 무효가 되어 있습니다.다만, 일부의 시스템은, 이 기능을 유효하게 하거나 에뮬레이트 한 채로 동작하고 있을 가능성이 있습니다.또한 글로벌 네임스페이스를 다른 방법으로 "오염"할 수도 있습니다.global키워드 또는$GLOBALS어레이를 설정합니다.

일단은register_globals그 자체가 예기치 않게 만들어 낼 것 같지는 않다nullGET, POST 및 cookie 값은 항상 스트링이기 때문에 변수입니다.''아직 돌아오다true부터isset세션 내의 변수는 프로그래머가 완전히 제어할 수 있어야 합니다.

둘째, 값을 가진 변수의 오염입니다.null이 문제가 되는 것은, 이전의 초기화를 덮어쓰는 경우 뿐입니다.초기화되지 않은 변수를 "덮어쓰기":null다른 곳에서 코드가 두 주를 구별하는 경우에만 문제가 될 수 있기 때문에 이 가능성 자체가 그러한 구별을 하는 것에 반대하는 주장이다.

4. get_defined_vars그리고.compact

및 와 같이 PHP에서 거의 사용되지 않는 함수를 사용하면 변수 이름을 배열의 키인 것처럼 처리할 수 있습니다.글로벌 변수의 경우 super-global 배열은 유사한 액세스를 허용하며 더 일반적입니다.이러한 접근 방식은 변수가 관련 범위에서 정의되지 않은 경우 다르게 동작합니다.

이러한 메커니즘 중 하나를 사용하여 변수 집합을 배열로 처리하면 일반 배열과 동일한 작업을 모두 수행할 수 있습니다.따라서 1을 참조하십시오.

이러한 함수의 동작을 예측하기 위해서만 존재하던 기능(예를 들어, 에 의해 반환되는 어레이에 키 「foo」가 있는 경우)get_defined_vars?")는 불필요한 것입니다.단순히 기능을 실행하여 악영향 없이 찾을 수 있기 때문입니다.

4a. 변수($$foo)

변수 집합을 연관 배열로 변환하는 함수와 완전히 동일하지는 않지만, "변수 변수"("이 다른 변수에 따라 명명된 변수에 할당")를 사용하는 대부분의 경우 대신 연관 배열을 사용하도록 변경할 수 있습니다.

변수 이름은 기본적으로 프로그래머가 값에 부여한 라벨입니다.실행 시에 결정하는 경우에는 실제로는 라벨이 아니라 키 값 저장소의 키입니다.보다 실질적으로 어레이를 사용하지 않으면 카운트, 반복 등을 할 수 없게 됩니다.또, 키 값 스토어 외부에 변수를 두는 것도 불가능해질 수 있습니다.이는 키 값 스토어가 덮어쓰기될 수 있기 때문입니다.$$foo.

어소시에이트 어레이를 사용하도록 변경되면, 이 코드는 솔루션 1에 대응합니다.간접 객체 속성 액세스(예:$foo->$property_name)는 솔루션 2로 대응할 수 있습니다.

5. isset타이핑이 훨씬 쉽다array_key_exists

이것이 실제로 관련이 있는지는 모르겠지만, 네, PHP의 함수명은 때때로 장황하고 일관성이 없을 수 있습니다.분명히, PHP의 선사 버전은 해시 키로서 함수 이름의 길이를 사용했기 때문에, Rasmus는 의도적으로 다음과 같은 함수 이름을 만들었습니다.htmlspecialchars그래서 특이한 숫자의 캐릭터를 가지고 있는 글자 수가...

그래도 적어도 Java는 쓰고 있지 않죠?;)

6. 초기화되지 않은 변수에는 유형이 있다.

변수 기본에 대한 설명서 페이지에는 다음과 같은 내용이 포함되어 있습니다.

초기화되지 않은 변수에는 사용되는 컨텍스트에 따라 해당 유형의 기본값이 지정됩니다.

Zend Engine에 "초기화되지 않았지만 알려진 유형"이라는 개념이 있는지 아니면 이것이 너무 많은 내용을 읽고 있는지 잘 모르겠습니다.

분명한 것은 초기화되지 않은 변수에 대해 해당 페이지에 설명된 행동은 값이 다음과 같은 변수의 동작과 동일하기 때문에 그들의 행동에 실질적인 차이가 없다는 것이다.null한 가지 예를 들자면 둘 다$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_function돌아올 수 있다null、 , 、echo와도 연락이 되지 않는다some_test반환했다true프로그래머의 의도는 언제인지 알아내는 것이었다.$result had never been set, but PHP does not allow them to do so.

However, there are other problems with this approach, which become clear if you add an outer loop:

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!';
    }
}

Because $result is never initialized explicitly, it will take on a value when the very first test passes, making it impossible to tell whether subsequent tests passed or not. This is actually an extremely common bug when variables aren't initialised properly.

To fix this, we need to do something on the line where I've commented that something's missing. The most obvious solution is to set $result to a "terminal value" that some_function can never return; if this is null, then the rest of the code will work fine. If there is no natural candidate for a terminal value because some_function has an extremely unpredictable return type (which is probably a bad sign in itself), then an additional boolean value, e.g. $found, could be used instead.

Thought experiment one: the very_null constant

PHP could theoretically provide a special constant - as well as null - for use as a terminal value here; presumably, it would be illegal to return this from a function, or it would be coerced to null, and the same would probably apply to passing it in as a function argument. That would make this very specific case slightly simpler, but as soon as you decided to re-factor the code - for instance, to put the inner loop into a separate function - it would become useless. If the constant could be passed between functions, you could not guarantee that some_function would not return it, so it would no longer be useful as a universal terminal value.

The argument for detecting uninitialised variables in this case boils down to the argument for that special constant: if you replace the comment with unset($result), and treat that differently from $result = null, you are introducing a "value" for $result that cannot be passed around, and can only be detected by specific built-in functions.

Thought experiment two: assignment counter

Another way of thinking about what the last if is asking is "has anything made an assignment to $result?" Rather than considering it to be a special value of $resultPerl의 "변수 표시"와 같은 변수에 대한 "메타데이터"라고 생각할 수 있습니다.그래서 보다isset라고 할 수 있다has_been_assigned_to, 그리고unset,reset_assignment_state.

하지만 그렇다면 왜 부울에서 멈추는가?테스트 통과 횟수를 알고 싶다면? 메타데이터를 정수로 확장하여 테스트 통과 횟수를 확인하면 됩니다.get_assignment_count그리고.reset_assignment_count...

이러한 기능을 추가하면 언어의 복잡성과 퍼포먼스가 균형을 이룰 수 있으므로 예상되는 유용성과 비교하여 신중하게 평가해야 합니다.A와 마찬가지로very_null상수는 매우 좁은 상황에서만 유용하며, 재팩터링에도 유사하게 내성이 있습니다.

희망적으로 분명한 질문은 왜 PHP 런타임 엔진이 이러한 것들을 추적하고 싶은지, 일반 코드를 사용하여 명시적으로 추적하도록 내버려두지 않고 미리 가정해야 하는지입니다.

특정 상황에서 어떤 비교 연산을 사용해야 할지 고민하다가 약간 당황할 때가 있습니다. isset()는 초기화되지 않았거나 명시적으로 늘 값에만 적용됩니다.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

콤팩트 언어 구성을 사용하여 늘 변수의 존재를 테스트할 수 있습니다.존재하지 않는 변수는 결과에 표시되지 않고 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. 개인적으로 나는 존재하지 않는 변수와 null 값을 가진 변수 사이에 의미적인 차이가 있는 페스트와 같은 상황은 피하고 싶다.PHP 및 기타 대부분의 언어는 존재하지 않는다고 생각합니다.

Explaining NULL, logically thinking

I guess the obvious answer to all of this is... Don't initialise your variables as NULL, initalise them as something relevant to what they are intended to become.

Treat NULL properly

NULL should be treated as "non-existant value", which is the meaning of NULL. The variable can't be classed as existing to PHP because it hasn't been told what type of entity it is trying to be. It may aswell not exist, so PHP just says "Fine, it doesn't because there's no point to it anyway and NULL is my way of saying this".

An argument

Let's argue now. "But NULL is like saying 0 or FALSE or ''.

Wrong, 0-FALSE-'' are all still classed as empty values, but they ARE specified as some type of value or pre-determined answer to a question. FALSE is the answer to yes or no,'' is the answer to the title someone submitted, and 0 is the answer to quantity or time etc. They ARE set as some type of answer/result which makes them valid as being set.

NULL is just no answer what so ever, it doesn't tell us yes or no and it doesn't tell us the time and it doesn't tell us a blank string got submitted. That's the basic logic in understanding NULL.

Summary

It's not about creating wacky functions to get around the problem, it's just changing the way your brain looks at NULL. If it's NULL, assume it's not set as anything. If you are pre-defining variables then pre-define them as 0, FALSE or "" depending on the type of use you intend for them.

Feel free to quote this. It's off the top of my logical head :)

Object properties can be checked for existence by property_exists

Example from a unit test:

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");
    }
}

As an addition to greatbigmassive's discussion of what NULL means, consider what "the existence of a variable" actually means.

In many languages, you have to explicitly declare every variable before you use it; this may determine its type, but more importantly it declares its scope. A variable "exists" everywhere in its scope, and nowhere outside it - be that a whole function, or a single "block".

Within its scope, a variable assigns some meaning to a label which you, the programmer, have chosen. Outside its scope, that label is meaningless (whether you use the same label in a different scope is basically irrelevant).

In PHP, variables do not need to be declared - they come to life as soon as you need them. When you write to a variable for the first time, PHP allocates an entry in memory for that variable. If you read from a variable that doesn't currently have an entry, PHP considers that variable to have the value NULL.

However, automatic code quality detectors will generally warn you if you use a variable without "initialising" it first. Firstly, this helps detect typos, such as assigning to $thingId but reading from $thing_id; but secondly, it forces you to consider the scope over which that variable has meaning, just as a declaration would.

Any code that cares whether a variable "exists" is part of the scope of that variable - whether or not it has been initialised, you as a programmer have given that label meaning at that point of the code. Since you're using it, it must in some sense "exist", and if it exists, it must have an implicit value; in PHP, that implicit value is null.

Because of the way PHP works, it is possible to write code that treats the namespace of existent variables not as a scope of labels you have given meaning to, but as some kind of key-value store. You can, for instance, run code like this: $var = $_GET['var_name']; $$var = $_GET['var_value'];. Just because you can, doesn't mean it's a good idea.

It turns out, PHP has a much better way of representing key-value stores, called associative arrays. And although the values of an array can be treated like variables, you can also perform operations on the array as a whole. If you have an associative array, you can test if it contains a key using array_key_exists().

You can also use objects in a similar way, dynamically setting properties, in which case you can use property_exists() in exactly the same way. Of course, if you define a class, you can declare which properties it has - you can even choose between public, private, and protected scope.

Although there is a technical difference between a variable (as opposed to an array key, or an object property) that hasn't been initialised (or that has been explicitly unset()) and one whose value is null, any code that considers that difference to be meaningful is using variables in a way they're not meant to be used.

isset checks if the variable is set and, if so, whether its value is not NULL. The latter part is (in my opinion) not within the scope of this function. There is no decent workaround to determine whether a variable is NULL because it is not set or because it is explicitly set to NULL.

Here is one possible solution:

$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

Other workaround is to probe the output of 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

I'm going to add a quick two cents to this. One reason this issue is confusing is because this scenario seems to return the same result with error reporting not on full:

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

You could assume from this result that the difference between $a = null and not defining $b at all is nothing.

Crank error reporting up:

NULL

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

Note: it threw an undefined variable error, but the output value of var_dump is still NULL.

PHP obviously does have an internal ability to distinguish between a null variable and an undefined variable. It seems to me that there should be a built in function to check for this.

I think the accepted answer is good for the most part, but if I was going to implement it I would write a wrapper for it. As previously mentioned in this answer, I have to agree that I haven't actually encountered a situation where this has been a problem. I seem to almost always end up in a scenario where my variables are either set and defined, or they aren't (undefined, unset, null, blank, etc). Not to say that a situation like this won't occur in future, but as it seems to be quite a unique issue I'm not surprised that the PHP devs haven't bothered to put this in.

If I run the following:

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

I get an error:

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

If I run the following:

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

I do not get the error.

If I have a variable that should be set, I usually do something like the following.

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

or

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

That way, later in the script, I can safely use $foo and know that it "is set", and that it defaults to null. Later I can if ( is_null($foo) ) { /* ... */ } if I need to and know for certain that the variable exists, even if it is null.

The full isset documentation reads a little more than just what was initially pasted. Yes, it returns false for a variable that was previously set but is now null, but it also returns false if a variable has not yet been set (ever) and for any variable that has been marked as unset. It also notes that the NULL byte ("\0") is not considered null and will return true.

Determine whether a variable is set.

If a variable has been unset with unset(), it will no longer be set. isset() will return FALSE if testing a variable that has been set to NULL. Also note that a NULL byte ("\0") is not equivalent to the PHP NULL constant.

I have to say in all my years of PHP programming, I have never encountered a problem with isset() returning false on a null variable. OTOH, I have encountered problems with isset() failing on a null array entry - but array_key_exists() works correctly in that case.

For some comparison, Icon explicitly defines an unused variable as returning &null so you use the is-null test in Icon to also check for an unset variable. This does make things easier. On the other hand, Visual BASIC has multiple states for a variable that doesn't have a value (Null, Empty, Nothing, ...), and you often have to check for more than one of them. This is known to be a source of bugs.

Try using

unset($v)

It seems the only time a variable is not set is when it is specifically unset($v). It sounds like your meaning of 'existence' is different than PHP's definition. NULL is certainly existing, it is NULL.

I don't agree with your reasoning about NULL, and saying that you need to change your mindset about NULL is just weird.

I think isset() was not designed correctly, isset() should tell you if the variable has been set and it should not be concerned with the actual value of the variable.

What if you are checking values returned from a database and one of the columns have a NULL value, you still want to know if it exists even if the value is NULL...nope dont trust isset() here.

likewise

$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() should have been designed to work like this:

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

this way we leave it up to the programmer to check types and not leave it up to isset() to assume its not there because the value is NULL - its just stupid design

I think the only full solution is to report notices with

error_reporting(E_ALL); // Enables E_NOTICE

But you will have to fix all the notices generated by undefined variables, constants, array keys, class properties amongst others. Once you have done that you won't have to worry about the difference between null and not declared variables, and the ambiguity dissappears.

Enabling notice reporting might not be a good alternative in all situations, but there are good reasons to enable it:

Why should I fix E_NOTICE errors?

In my case was more than a year working in a proyect without it, but was used to be careful about declaring variables, so it was fast to transition.

According to the PHP Manual for the empty() function, "Determine whether a variable is considered to be empty. A variable is considered empty IF IT DOES NOT EXIST or if its value equals FALSE. empty() does not generate a warning if the variable does not exist." (My emphasis.) That means the empty() function should qualify as the "best way to test a variable's existence in PHP", per the title Question.

However, this is not good enough, because the empty() function can be fooled by a variable that does exist and is set to NULL.

I'm interrupting my earlier answer to present something better, because it is less cumbersome than my original answer (which follows this interruption, for comparing).

  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
  }

Two simple lines of code can use the above function to reveal if a variable is undefined:

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

You can follow those two lines with anything appropriate, such as this example:

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

I wanted to put the call to ob_start() and the ($testvar===null) inside the function, and simply pass the variable to the function, but it doesn't work. Even if you try to use "pass by reference" of the variable to the function, the variable BECOMES defined, and then the function can never detect that it previously had been undefined. What is presented here is a compromise between what I wanted to do, and what actually works.

The preceding implies that there is another way to always avoid running into the "Undefined variable" error message. (The assumption here is, preventing such a message is why you want to test to see if a variable is undefined.)

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

Just call that function before doing something to your $testvar:

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

The newly-instantiated variable's value is set to null, of course!

(Interruption ends)

So, after some studying and experimenting, here is something guaranteed to work:

 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
 }

The explanation: A variable $er is initialized to a default value of "no error". A "handler function" is defined. If the $testvar (the variable we want to know whether or not is undefined) passes the preliminary empty() function test, then we do the more thorough test. We call the set_error_handler() function to use the previously-defined handler function. Then we do a simple identity-comparison involving $testvar, WHICH IF UNDEFINED WILL TRIGGER AN ERROR. The handler function captures the error and specifically tests to see if the reason for the error is the fact that the variable is undefined. The result is placed in the error-information variable $er, which we can later test to do whatever we want as a result of knowing for sure whether or not $testvar was defined. Because we only need the handler function for this limited purpose, we restore the original error-handling function. The "myHndlr" function only needs to be declared once; the other code can be copied to whatever places are appropriate, for $testvar or any other variable we want to test this way.

THE only way to know if a variable is defined in current scope ($GLOBALS is not trustworthy) is array_key_exists( 'var_name', get_defined_vars() ).

I prefer using not empty as the best method to check for the existence of a variable that a) exists, and b) is not null.

if (!empty($variable)) do_something();

ReferenceURL : https://stackoverflow.com/questions/418066/best-way-to-test-for-a-variables-existence-in-php-isset-is-clearly-broken

반응형