로부터 isset()
문서 :
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()
함수 에 대해 이야기하고있는 모호성을 볼 수 있습니다 . 다음은이 세 가지의 결과입니다 var_dump()s
.
array(1) {
["b"]=>
NULL
}
bool(false)
bool(false)
추가 편집 : 두 가지.
하나는 유스 케이스입니다. UPDATE
배열의 키는 테이블의 열이고 배열의 값은 각 열에 적용되는 값인 SQL 문의 데이터로 변환 됩니다. 테이블의 열은 배열에 값 NULL
을 전달하여 표시되는 값을 보유 할 수 있습니다 NULL
. 존재하지 않는 배열 키와 배열 값을 구분하는 방법 이 필요 합니다 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()
에 따라, 그 문서 , 비슷하게 작동 array_key_exists()
이 제대로 설정되는과에 세트가없는 사이에 구별 점에서 NULL
.)
답변
확인중인 변수가 전역 범위에 있으면 다음을 수행 할 수 있습니다.
array_key_exists('v', $GLOBALS)
답변
다양한 토론과 답변에 대한 개요를 제공하려고합니다.
isset
사용할 수있는 모든 방법을 대체 할 수있는 질문에 대한 단일 답변은 없습니다 . 일부 유스 케이스는 다른 기능으로 해결되는 반면, 다른 유스 케이스는 정밀 조사를지지하거나 코드 골프를 넘어 모호한 가치를 지니지 않습니다. “파손 된”또는 “일관되지 않은”것과는 달리, 다른 유스 케이스는 왜 isset
반응 null
이 논리적 행동 인지를 보여줍니다 .
실제 사용 사례 (솔루션 포함)
1. 배열 키
배열은 마치 변수처럼 취급 unset
하고 변수의 집합처럼 취급 될 수 있습니다 isset
. 그러나 반복, 계산 등이 가능하므로 결 측값은 값이 아닌 값과 다릅니다 null
.
이 경우의 대답은 대신에 사용하는 array_key_exists()
것입니다isset()
.
이것은 배열을 함수 인수로 검사하기 때문에 배열 자체가 존재하지 않으면 PHP는 여전히 “알림”을 발생시킵니다. 경우에 따라 각 차원을 먼저 초기화해야한다고 주장 할 수 있으므로 통지가 제대로 수행되고 있습니다. 다른 경우 array_key_exists
에는 배열의 각 차원을 차례로 확인한 “재귀” 함수는이를 피하지만 기본적으로와 동일합니다 @array_key_exists
. 또한 null
값을 처리하는 데 다소 접 합니다.
2. 객체 속성
“객체 지향 프로그래밍”의 전통적인 이론에서 캡슐화와 다형성은 객체의 주요 속성입니다. PHP의 같은 클래스 기반 OOP 구현에서, 캡슐화 된 속성은 클래스 정의의 일부로 선언하고, 주어진 액세스 수준 ( public
, protected
또는 private
).
그러나 PHP를 사용하면 배열의 키처럼 객체에 속성을 동적으로 추가 할 수 있으며 일부 사람들은 비슷한 클래스에서 객체가없는 객체 (기술적으로는 내장 stdClass
또는 인스턴스 가없는 메소드)를 사용합니다 연관 배열 방법. 이것은 특정 속성이 주어진 객체에 추가되었는지 함수가 알고 싶어하는 상황으로 이어집니다.
배열 키와 마찬가지로 객체 속성을 확인하기위한 솔루션이 언어에 합리적으로 충분히 포함되어 있습니다property_exists
.
토론이 가능한 정당하지 않은 사용 사례
3. register_globals
글로벌 네임 스페이스의 기타 오염
이 register_globals
기능은 HTTP 요청 (GET 및 POST 매개 변수 및 쿠키)의 측면에 따라 이름이 결정되는 전역 범위에 변수를 추가했습니다. 이로 인해 버그가 많고 안전하지 않은 코드가 생길 수 있으며, 이는 2000 년 8 월에 릴리스 된 PHP 4.2 이후 기본적으로 비활성화되어 2012 년 3 월에 출시 된 PHP 5.4 에서 완전히 제거 된 이유 입니다. 그러나 일부 시스템은이 기능을 사용하거나 에뮬레이트 한 상태로 계속 실행 중일 수 있습니다. global
키워드 또는 $GLOBALS
배열을 사용하여 다른 방식으로 전역 네임 스페이스를 “폴링”할 수도 있습니다 .
첫째, register_globals
자체가 예기치 않게 생산할 가능성이 null
는 GET, POST 이후, 변수 및 쿠키 값은 항상 (와 문자열이 될 것입니다 ''
여전히 반환 true
에서 isset
), 세션 변수는 프로그래머의 통제하에 완전히 있어야한다.
둘째, 값 null
이 있는 변수의 오염은 이전 초기화를 덮어 쓰는 경우에만 문제가됩니다. 초기화되지 않은 변수를 “덮어 쓰기”하는 null
것은 다른 곳의 코드가 두 상태를 구별하는 경우에만 문제가 될 수 있으므로, 이러한 가능성은 그 자체 로 그러한 구별을 만드는 것에 반대 하는 주장 입니다.
4. get_defined_vars
그리고compact
PHP에서 드물게 사용되는 몇 가지 함수 (예 : get_defined_vars
and compact
)를 사용하면 변수 이름을 배열의 키인 것처럼 취급 할 수 있습니다. 전역 변수의 경우 수퍼 전역 배열$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
. 하나의 예를 선택하려면, 모두 $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
되더라도 원에 도달하지 못할 가능성이 있습니다 . 프로그래머의 의도는 설정되지 않은 시간 을 감지하는 것이지만 PHP는 그렇게 할 수 없습니다.some_test
true
$result
그러나이 방법에는 다른 문제가 있으며 외부 루프를 추가하면 분명해집니다.
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
대신 사용할 수 있습니다.
하나의 실험 : very_null
상수
PHP는 이론적 null
으로 터미널 값으로 사용 하기위한 특별한 상수를 제공 할 수 있습니다. 아마도 함수에서 이것을 반환하는 것은 불법이거나로 강제 변환 null
될 것이며 아마도 함수 인수로 전달하는 경우에도 마찬가지입니다. 이렇게하면이 특정 사례가 약간 더 간단 해지지 만 코드를 리팩터링하기로 결정하자마자-예를 들어 내부 루프를 별도의 함수에 넣으면 쓸모가 없게됩니다. 함수간에 상수를 전달할 수 있으면 some_function
반환하지 않을 것이라고 보장 할 수 없으므로 더 이상 범용 터미널 값으로 유용하지 않습니다.
이 경우 초기화되지 않은 변수를 감지하기위한 인수는 해당 특수 상수에 대한 인수로 귀결됩니다. 주석을로 바꾸고 unset($result)
이를 다르게 처리하는 경우 전달할 수없는 $result = null
“값”을 가져 $result
오는 것만 가능합니다. 특정 내장 기능에 의해 감지됩니다.
실험 2 : 할당 카운터
마지막 if
질문 에 대해 생각하는 또 다른 방법 은 “무엇이 할당되어 $result
있습니까?”입니다. 이 값을의 특별한 값으로 생각하기보다는 $result
이것을 Perl의 “variable tainting”과 같은 변수 에 대한 “메타 데이터”로 생각할 수 있습니다. 그래서보다는 isset
당신이 그것을 호출 할 수 있습니다 has_been_assigned_to
, 그리고보다는 unset
, reset_assignment_state
.
그렇다면 그렇다면 부울에 멈추는 이유는 무엇입니까? 시험이 몇 번이나 통과 했는지 알고 싶다면 어떻게해야합니까? 당신은 단순히 메타 데이터를 정수로 확장 할 수 get_assignment_count
있고 reset_assignment_count
…
분명히 이러한 기능을 추가하면 언어의 복잡성과 성능이 저하 될 수 있으므로 예상되는 유용성과 비교하여 신중하게 평가해야합니다. very_null
상수 와 마찬가지로 매우 좁은 환경에서만 유용하며 리팩토링에 유사하게 저항합니다.
희망적으로 명백한 질문은 PHP 런타임 엔진이 일반 코드를 사용하여 명시 적으로 수행하지 않고 그러한 것들을 추적하고 싶다고 미리 가정해야하는 이유입니다.
답변
때로는 주어진 상황에서 어떤 비교 연산을 사용할 것인지 알아 내려고 조금씩 잃어 버렸습니다. 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
답변
간결한 언어 구문을 사용하여 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 ()를 사용할 수도 있습니다.
Btw 개인적으로 나는 존재하지 않는 변수와 null 값을 가진 변수 사이에 의미 론적 차이가있는 전염병과 같은 상황을 피할 것입니다. PHP와 다른 대부분의 언어는 존재한다고 생각하지 않습니다.
답변
논리적으로 생각하고 NULL을 설명
이 모든 것에 대한 명백한 대답은 다음과 같습니다. 변수를 NULL로 초기화하지 말고 의도 된 것과 관련이있는 것으로 초기화하십시오.
NULL을 올바르게 처리
NULL은 “존재하지 않는 값”으로 취급되어야하며 이는 NULL의 의미입니다. 변수는 어떤 유형의 엔티티인지 알 수 없으므로 PHP에 기존 변수로 분류 될 수 없습니다. 그것은 존재하지 않을 수도 있으므로, PHP는 단지 “좋아요. 아무 의미가 없기 때문에 아닙니다. NULL은 이것을 말하는 방법입니다.”
논쟁
지금 논쟁합시다. “하지만 NULL은 0 또는 FALSE 또는“와 같습니다.”
잘못된 0-FALSE- ”는 여전히 빈 값으로 분류되지만 일부 유형의 값 또는 질문에 대한 미리 결정된 답변으로 지정됩니다. FALSE 는 예 또는 아니오에 대한 답이고, ” 는 누군가가 제출 한 제목에 대한 답이며, 0 은 수량 또는 시간 등에 대한 답입니다. 어떤 유형의 답변 / 결과로 설정되어 설정 한대로 유효합니다.
NULL은 응답이 없으며 예 또는 아니오를 알려주지 않으며 시간을 알려주지 않으며 빈 문자열이 제출되었음을 알려주지 않습니다. 이것이 NULL을 이해하는 기본 논리입니다.
요약
문제를 해결하기 위해 엉뚱한 함수를 만드는 것이 아니라 뇌가 NULL을 보는 방식을 바꾸는 것입니다. NULL이면 아무것도 설정되지 않은 것으로 가정합니다. 변수를 사전 정의하는 경우 사용하려는 유형에 따라 0, FALSE 또는 “”로 사전 정의하십시오.
이 말을 인용하십시오. 내 논리적 인 머리 꼭대기에서 벗어났습니다. 🙂
답변
개체 속성에 의해 존재 여부를 확인할 수 있습니다 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");
}
}
답변
에 추가로 무엇을 NULL 수단의 greatbigmassive의 토론 , 실제로 무엇을 의미하는지 “변수의 존재를”고려하십시오.
많은 언어에서 모든 변수를 사용하기 전에 명시 적으로 선언해야합니다 . 이것에 의해 그 타입이 결정될 수 있지만,보다 중요하게는 scope를 선언합니다 . 변수는 그 범위 내 어디에서나 “존재”하고, 그 밖의 다른 곳에서는 전체 기능 또는 단일 “블록”이됩니다.
범위 내에서 변수 는 프로그래머가 선택한 레이블에 의미를 부여합니다 . 해당 범위를 벗어나면 해당 레이블은 의미가 없습니다 (다른 범위에서 동일한 레이블을 사용하는지 여부는 기본적으로 관련이 없습니다).
PHP에서는 변수를 선언 할 필요가 없습니다. 변수는 필요할 때 바로 작동합니다. 변수에 처음 쓸 때 PHP는 해당 변수에 대한 항목을 메모리에 할당합니다. 현재 엔트리가없는 변수를 읽는다면, PHP는 그 변수가 value를 갖는 것으로 간주합니다 NULL
.
그러나 자동 코드 품질 감지기는 변수를 먼저 “초기화”하지 않고 변수를 사용하는 경우 일반적으로 경고합니다. 첫째, 이것은 할당 $thingId
하지만 읽는 것과 같은 오타를 감지하는 데 도움이됩니다 $thing_id
. 그러나 두 번째로, 선언처럼 변수가 의미가있는 범위를 고려해야합니다.
변수가 “존재”하는지 여부를 관리하는 모든 코드는 변수의 범위의 일부입니다. 초기화 여부에 관계없이 프로그래머는 코드의 해당 지점에서 레이블 의미를 부여했습니다. 당신이 그것을 사용하고 있기 때문에, 어떤 의미에서 “존재”하고, 존재한다면, 그것은 암묵적인 값을 가져야합니다; PHP에서 암시 적 값은 null
입니다.
PHP가 작동하는 방식 때문에 존재하는 변수의 네임 스페이스를 의미있는 레이블 범위가 아니라 일종의 키-값 저장소로 처리하는 코드를 작성할 수 있습니다. 예를 들어 다음과 같은 코드를 실행할 수 있습니다 $var = $_GET['var_name']; $$var = $_GET['var_value'];
. 당신이 할 수 있다고해서 그것이 좋은 생각 인 것은 아닙니다.
PHP는 연관 배열이라고 불리는 키-값 저장소를 표현하는 훨씬 더 좋은 방법을 가지고 있습니다. 배열의 값을 변수처럼 취급 할 수 있지만 배열에 대한 작업을 전체적으로 수행 할 수도 있습니다. 연관 배열이있는 경우을 사용하여 키가 포함되어 있는지 테스트 할 수 있습니다 array_key_exists()
.
비슷한 방식으로 객체를 사용하여 속성을 동적으로 설정할 수 있으며,이 경우 property_exists()
정확히 동일한 방식으로 사용할 수 있습니다 . 물론, 당신이 클래스를 정의하는 경우, 당신은 한 어떤 속성을 선언 할 수 있습니다 당신도 선택할 수 있습니다 – public
, private
및 protected
범위.
초기화되지 않은 (또는 명시 적으로 ) 변수 (배열 키 또는 객체 속성과 달리)와 기술적으로 차이 가 있지만 그 차이를 의미있는 것으로 간주하는 모든 코드 변수를 사용하지 않는 방식으로 사용하고 있습니다.unset()
null
