property_exists 와 isset 의 차이에 대한 자세한 분석과 각각의 장점과 단점은 무엇입니까?
property_exists () 및 isset () 은 종종 "객체 속성이 존재하는지 판단"에 사용됩니다. 그러나 두 의미는 동일하지 않다. 전자는 "속성이 객체 또는 클래스에 선언/존재하는지 여부"에 중점을두고, 후자는 "변수 또는 속성이 설정되어 있고 null 이 아닌지"에 중점을 둔다. 이 차이를 이해하면 빈 포인터, 초기화되지 않은 속성 및 마법 방법으로 인한 함정을 피할 수 있습니다.
한 문장 결론
- property_exists (\ $ obj, 'x') : 값이 무엇이든 ( 널 , 초기화되지 않은 유형 속성, 보이지 않는 개인/보호 된 속성 포함) "이 속성이 객체에 존재하는 한"마치 진실을 반환합니다.
- isset (\ $ obj-> x) : " x가 설정되어 있고 null이 아닌"경우에만 true를 반환합니다. NULL , UNSET 및 UNITIALID 유형 속성은 모두 False를 반환합니다. __isset ()는 과부하 된 속성에 대해 트리거됩니다.
핵심 비교 테이블
| 장면 | property_exists | ISSET |
|---|---|---|
| 속성 선언이 존재하고 값은 null 입니다. | 진실 | 진실 |
| 속성 선언이 존재하고 값은 null 입니다 | 진실 | 거짓 |
| 속성은 선언/존재하지 않습니다 | 거짓 | 거짓 (그리고 __isset을 트리거 할 수 있음) |
| 개인/보호 특성 | 진실 | 표시되는지/구현되었는지 __isset (일반적으로 거짓)에 따라 다릅니다. |
| 유형 속성 (초기화되지 않음) | 진실 | false (직접 액세스는 오류를 던지고 Isset은 거짓입니다) |
| 동적 특성 (8.2+ 기본 감가 상각 된 생성) | 존재는 사실입니다 | 그것이 존재하고 무효가 되지 않을 때는 사실입니다 |
| 마법 방법을 트리거할지 여부 | __get/__ isset을 트리거하지 않습니다 | __isset 을 트리거 할 수 있습니다 |
| 클래스 이름 문자열에 사용할 수 있습니다 | 예 (클래스의 선언 된 속성을 확인하십시오) | 아니요 (변수/객체 액세스가 필요합니다) |
| 성능 (대략) | 기능 호출, 약간 느리게 | 언어 구조, 매우 빠릅니다 |
최소 예 : 한 눈에 차이를 참조하십시오
<?php
class User {
public ?string $nickname = null; // 선언,하지만 null
private int $age = 18; // 개인 속성
}
\$u = new User();
var_dump(property_exists(\$u, 'nickname')); // true:재산“존재하다”
var_dump(isset(\$u->nickname)); // false:가치는입니다 null
var_dump(property_exists(\$u, 'age')); // true:그렇더라도 private 전적으로“존재하다”
var_dump(isset(\$u->age)); // false:보이지 않습니다,구현되지 않았습니다 __isset
var_dump(property_exists(\$u, 'email')); // false:언급되지 않았습니다/不존재하다
var_dump(isset(\$u->email)); // false:대상이 아닙니다
유형의 속성과의 상호 작용
PHP 7.4이므로 유형 속성은 "선언되지만 초기화되지 않음"할 수 있습니다. 현재 :
- property_exists : true (선언이 존재하기 때문에).
- isset (\ $ obj-> prop) : false ; \ $ obj-> prop를 직접 읽으면 오류가 발생합니다. 초기화 전에 입력 한 속성 ... 액세스하지 않아야합니다 .
<?php
class Post {
public string $title; // 초기화되지 않았습니다
}
\$p = new Post();
var_dump(property_exists(\$p, 'title')); // true
var_dump(isset(\$p->title)); // false
// echo \$p->title; // 치명적인 오류:초기화되지 않았습니다的类型재산
마법 방법과의 협력
클래스가 속성 과부하 ( __get/__ set/__ isset )를 구현할 때 :
- property_exists는 __get 또는 __isset을 트리거 하지 않으며 "실제 속성 테이블"만 살펴 봅니다.
- isset (\ $ obj-> x)은 __isset ( 'x')을 호출하여 "세트로 간주되는지 여부"를 사용자 정의 할 수 있도록 시도합니다.
<?php
class Box {
private array \$data = ['a' => null, 'b' => 1];
public function __isset(string \$name): bool {
// 사용자 정의하십시오:只要键존재하다就算“세트”(哪怕가치는입니다 null)
return array_key_exists(\$name, \$this->data);
}
}
\$box = new Box();
var_dump(isset(\$box->a)); // true(왜냐하면 __isset 반품 true)
동적 특성 및 PHP 8.2+
PHP 8.2에서 시작하여 일반 클래스에 대한 속성을 동적으로 생성합니다 ( \ $ obj-> foo = 1 및 클래스에는 foo 가 없습니다)은 기본적으로 경고를 폐기합니다. 권장 관행 :
- 명시 적으로 속성을 선언합니다. 또는
- 클래스에서 #[AllowDynamicProperties]를 사용하십시오. 또는
- STDCLASS / NEXICT 속성 스토리지 컨테이너를 사용하십시오.
객체 에이 속성이 있으면 :
- property_exists (\ $ obj, 'foo')는 사실 입니다.
- ISSET (\ $ obj-> foo)는 그 값이 널 여부 에 따라 다릅니다.
각각 자체의 장점과 단점이 있습니다
property_exists
- 장점 : 의미론은 명확하고 (존재하는지/선언하든), 개인/보호 된 속성을 확인하고 클래스 이름 문자열을 확인할 수 있으며 마법 방법을 유발하지 않습니다.
- 단점 : "초기화/비 널", 기능 호출이 오버 헤드인지, 더 많은 "보수적 인"반환이 과부하 된 속성으로 반환하는지 판단하는 것은 불가능합니다.
ISSET
- 장점 : 매우 빠르며, __isset 과 협력하여 비즈니스 의미를 표현할 수 있으며 "NO NULLE IS ASAVE"에 대한 직관적 인 판단.
- 단점 : null은 항상 "unset"으로 간주되며, "null value"를 "누락"과 혼동하기 쉽습니다. 클래스 이름 문자열에는 사용할 수 없습니다. 초기화되지 않은 유형 속성을 쉽게 밟을 수 있습니다 (직접 액세스는 오류가 발생합니다).
일반적인 오용과 함정
- "Evential"을 "사용 가능한"것으로 취급 : Property_Exists로 True를 반환한다고해서 값이 읽을 수 있거나 초기화되었음을 의미하지는 않습니다.
- Null을 "누락"으로 취급하십시오 : ISSET은 NULL을 볼 수 없으며 Array_Key_Exists 및 Ternary/Empty Merge 연산자와 조정해야합니다.
- 가시성/마법 방법을 무시하십시오 . ISSET은 표시되지 않거나 __isset 에 의해 다시 작성 될 수 있으므로 False를 반환 할 수 있습니다.
- 8.2+의 동적 특성 : 의도하지 않은 동적 특성을 만들면 더 이상 사용되지 않는 경고가 생성되며 명시 적으로 선언하는 것이 좋습니다.
실용적인 모델 및 모범 사례
1) "선언이 존재한다"는 것을 확인하지만 가치에 신경 쓰지 않는다.
<?php
if (property_exists(\$user, 'id')) {
// 초기화되었는지 여부를 추가로 결정할 수 있습니다/아니요 null
}
2) "사용 가능 및 비 널"확인
<?php
if (isset(\$user->id)) {
// 안전한 사용 \$user->id
}
3) "null"과 "missing"(배열/데이터 매핑)을 구별해야합니다.
<?php
// 배열 장면:사용하십시오 array_key_exists
\$data = ['a' => null];
var_dump(isset(\$data['a'])); // false
var_dump(array_key_exists('a', \$data)); // true:键존재하다,가치는입니다 null
4) 존재와 가용성을 모두 판단해야합니다.
<?php
if (property_exists(\$dto, 'amount') && isset(\$dto->amount)) {
// 동시에 만나십시오“声明존재하다”그리고“아니요 null 사용 가능”
}
5) 인터페이스/DTO를위한 안정적인 쓰기 방법 (유형 속성 포함)
<?php
class OrderDTO {
public ?int \$amount = null; // 명백한 널 의미론
}
\$o = new OrderDTO();
// 자격 및 불이행
\$value = \$o->amount ?? 0; // 빈 합병:null 또는 설정되지 않은 경우 기본값을 제공하십시오
언제 누구를 선택해야합니까?
- "구조 검증"또는 "반사 점검" (클래스가 특정 속성을 선언하거나 인터페이스와 호환되는지 여부) : property_exists를 사용하십시오.
- "비즈니스 가용성 판단" (부동산이 설정되어 있고 NULL이 아닌 경우에만 사용할 수 있음) : ISSET을 먼저 사용하십시오.
- 유형 속성에 직면 : 시작되지 않은 독서를 직접 읽지 마십시오. ISSET은 거짓을 반환하고 보안 센트리입니다.
- 과부하와 협력해야합니다 . __isset을 구현하여 사용자 정의 "가용성"규칙.
결론
"존재"를 "가용성"과 분리하는 것은 Property_Exists 또는 ISSET을 선택하는 열쇠입니다. 전자는 "이 속성입니까?" 후자는 "지금 사용될 수있다"고 대답했다. 시맨틱으로 도구를 선택하면 코드가 더 안정적이고 유지 관리가 쉬워집니다.