내 PHP 코드에서 assert를 사용해야합니까?


87

동료가 if 문을 사용하고 예외를 던졌을 때 라이브러리 내 에서 assert 명령을 몇 번 추가했습니다 . (이전에 assert에 대해 들어 본 적이 없습니다.) 다음은 그가 어떻게 사용했는지에 대한 예입니다.

assert('isset($this->records); /* Records must be set before this is called. */');

나는했을 것이다 :

if (!isset($this->records)) {
    throw new Exception('Records must be set before this is called');
}

assert에 대한 PHP 문서를 읽으면 assert가 활성화되어 있는지 확인하고 assert를 사용하기 전에 핸들러를 추가하는 것이 좋습니다. 그가이 일을 한 곳을 찾을 수 없습니다.

그래서, 제 질문은 위와 같은 좋은 아이디어를 사용하고 있으며 if 및 예외 대신에 더 자주 사용해야합니까?

또 다른 메모는 우리가 참여하지 않을 수도있는 프로젝트 (라이브러리는 오픈 소스 임)를 포함하여 다양한 프로젝트 및 서버에서 이러한 라이브러리를 사용할 계획입니다. 이것이 assert를 사용하는 데 차이가 있습니까?


정말입니까 'isset(코드 라인 assert)? isset(작은 따옴표없이) 뿐만 아니라 '?
Peter Mortensen 19

답변:


79

대부분의 언어에 적용 할 수있는 경험 법칙 (내가 모호하게 알고있는 모든 것)은 an assert은 조건이 항상 참 이라고 주장하는 데 사용되는 반면 an if은 때때로 실패 할 것이라고 생각할 수있는 경우 적절하다는 것입니다.

이 경우 주어진 메서드가 호출되기 전에 항상 설정 되어야 assert하므로 상황에 대한 나의 약한 이해를 바탕으로 적절 하다고 말할 수 있습니다. 따라서 레코드 설정 실패는 런타임 조건이 아니라 프로그램의 버그입니다. 여기서는 로 보호되고있는 코드를 야기 할 수 없음 가능한 프로그램 실행 경로가 없다는 것을 (충분한 테스트를) 확인하는 데 도움이되는 없이 호출 될 수 있었다 세트를 가지고.recordsassertassertrecords

사용하는 이점 assert등은 대향 ifassert일반적으로 생산 코드 따라서 오버 헤드 감소 해제 할 수있다. 가장 잘 처리되는 상황 if은 프로덕션 시스템에서 런타임 중에 발생할 수 있으므로이를 끌 수 없어도 손실되는 것은 없습니다.


4
여기에 추가하려면 프로덕션 코드에서 어설 션을 비활성화하지 않을 수 있습니다. 왜냐하면 "이런 일이 발생하지 않아야합니다"조건이 그대로 유지되도록하기 때문입니다. 사용자가 존재하지 않아야하는 실행 경로를 계속 따라 가도록하는 것보다 어설 션에서 애플리케이션을 중지하는 것이 더 나을 수 있습니다.
derekerdmann 2010

2
@derekerdmann : 맞습니다. 일부 어설 션의 경우이를 로그 (프로덕션)하거나 경고를 인쇄 (개발 환경)하는 것으로 충분할 수 있습니다. 그러나 종종 어설 션은 보안 관련 코드도 보호하므로 assert_options(ASSERT_BAIL). 어쨌든 수동 if / throw 해결 방법보다 빠릅니다.
마리오

4
@derekerdmann 나는 이것에 동의하지 않을 것입니다 (php에서 assert ()를 사용하는 맥락에서). assert ()는 모든 문자열 인수를 PHP 코드로 취급하므로 이것은 (이론적으로) 임의의 코드를 주입하고 실행할 수 있기 때문에 큰 취약성 차이입니다. IMHO, 단언은 프로덕션에서 꺼야합니다
Vitaliy Lebedev 2013 년

2
@VitaliyLebedev 주입에 취약하지 않으려면 어설 션 할 문자열을 전달하지 마십시오.
Damon Snyder

9
파티에 늦었지만 PHP.net은 "어설 션은 디버깅 기능으로 만 사용해야합니다."라고 말합니다.
Koen.

25

주장을 "권한 의견"으로 생각하십시오. 다음과 같은 댓글보다는

// Note to developers: the parameter "a" should always be a number!!!

사용하다:

assert('is_numeric(a) /* The parameter "a" should always be a number. */');

의미는 정확히 동일하고 정확히 동일한 청중을 대상으로하지만 첫 번째 주석은 쉽게 잊거나 무시됩니다 (느낌표 수에 관계없이). 반면 "파워 주석"은 사람이 읽고 이해할 수있을뿐만 아니라 또한 개발 중에 지속적으로 머신 테스트를 거치며 코드 및 작업 습관에서 어설 션 처리를 잘 설정하면 무시되지 않습니다.

이렇게 보면 어설 션은 if (error) ... 및 예외와 완전히 다른 개념이며 공존 할 수 있습니다.

예, 코드에 주석을 달아야하며 가능할 때마다 "강력한 주석"(어설 션)을 사용해야합니다.


개발시 테스트 할 때 항상 좋은 조건을 어설 션에 전달하지만 프로덕션에서는 어설 션이 꺼져 있으면 어떤 사용자가 테스트 할 때 생각하지 않은 다른 조건을 통과하면 어떨까요? 아니면 항상 assert를 유지해야하는데 수표를 작성하는 것과 같지 않습니까?
Dariux

그러면 프로그램이 실패합니다. 언어 및 개발 환경의 if 문과 오류 처리 기능을 사용하여 올바르게 수정하십시오. 주장은 문제를 발견 할 수 있으며 문제를 해결하는 더 좋은 방법이 있습니다.
DaveWalley 2014

PHP 7.2에서 평가를 위해 assert에 문자열을 전달하는 것은 더 이상 사용되지 않습니다. 매우 편리해 보였기 때문에 슬프다.
Jannie Theunissen

16

그것은 전적으로 개발 전략에 달려 있습니다. 대부분의 개발자는 assert()다운 스트림 단위 테스트를 인식하지 못하고 사용합니다. 그러나 사전 예방적이고 내장 된 테스트 체계가 때때로 유리할 수 있습니다.

assert는 활성화 및 비활성화가 가능하기 때문에 유용합니다. 그러한 어설 션 처리기가 정의되지 않으면 성능이 저하되지 않습니다. 동료에게는 하나가 없으므로 개발 환경에서 임시로 활성화하는 코드를 고안해야합니다 (E_NOTICE / E_WARNING이 켜져 있으면 어설 션 처리기가 있어야 함). 내 코드가 혼합 변수 유형을 위장 할 수없는 경우 가끔 사용합니다. 일반적으로 약한 유형의 PHP에서는 엄격한 유형을 사용하지 않지만 무작위 사용 사례가 있습니다.

 function xyz($a, $b) {
     assert(is_string($a));
     assert(is_array($b));

예를 들어 유형 지정자의 부족을 보상합니다 string $a, array $b. PHP5.4는이를 지원하지만 확인하지는 않습니다.


"php 5.4는 그것들을 가지지 만 확인하지 않습니다"는 무슨 뜻입니까?
Kzqai

1
PHP 5.4는 assert를 지원하고 확인합니다.
DaveWalley

7

Assert는 if개발 중 디버깅에만 사용되기 때문에 예외 와 같은 일반적인 흐름 제어를 대체하지 않습니다 .


6

7 이전의 PHP에서 assert와 관련된 중요한 참고 사항입니다. assert 구문을 사용하는 다른 언어와 달리 PHP는 assert 문을 완전히 던지지 않습니다.이를 함수로 처리합니다 (assertion에 의해 호출 된 함수에서 debug_backtrace () 수행). 어설 션을 끄는 것은 엔진에서 아무 일도하지 않도록 함수를 핫 와이어하는 것처럼 보입니다. PHP 7은 더 일반적인 값인 1 (on) 또는 -1 (off) 대신 zend.assertions를 0으로 설정하여이 동작을 에뮬레이션하도록 만들 수 있습니다.

문제는 assert가 임의의 인수를 취한다는 점에서 발생합니다.하지만 인수가 문자열이 아니면 assert는 assert가 켜져 있든 꺼져 있든 식의 결과를 가져옵니다. 다음 코드 블록으로이를 확인할 수 있습니다.

<?php
  function foo($a) { 
    echo $a . "\n"; 
    return TRUE;
  }
  assert_options(ASSERT_ACTIVE, FALSE);

  assert( foo('You will see me.'));
  assert('foo(\'You will not see me.\')');

  assert_options(ASSERT_ACTIVE, TRUE);

  assert( foo('Now you will see'));
  assert('foo(\'both of us.\')');

assert의 의도를 감안할 때 이것이 버그이며 assert가 PHP 4에서 다시 도입 된 이후로 언어에 있었기 때문에 오랫동안 지속되어 왔습니다.

assert에 전달 된 문자열은 그와 함께 제공되는 모든 성능 영향 및 위험과 함께 평가되지만 PHP에서 필요한 방식으로 작동하도록 assert 문을 얻는 유일한 방법입니다 (이 동작은 PHP 7.2에서 사용되지 않음).

편집 : PHP 7 및 7.2의 변경 사항을 기록하도록 위 변경


1
PHP 7에는 zend.assertions완전히 꺼지는 ini 설정 이 있습니다 assert().
Kontrollfreak 2015

그것은 좋은 소식입니다. 그러나 문서에 따르면 PHPUnit에 대한 패치가 주문 된 것처럼 보입니다. PHP 5.x에서 어설 션이 실패 할 때 AssertionException을 발생시키는 어설 션 콜백 핸들러를 추가합니다. 단위 테스트는 상관없이 PHP 5.x를 또는 7에서 실행 여부에 주석 @expectedException의 AssertionException를 사용할 수있는이 방법
마이클 모리스

3

Assert는 디버깅에 유용하므로 개발에만 사용해야합니다. 따라서 원하는 경우 웹 사이트 개발에 사용할 수 있지만 라이브 웹 사이트에는 예외를 사용해야합니다.


7
그러나 코드에는 여전히 어설 션이 있습니다. 프로덕션 환경에서는 활성화되지 않습니다.
aaronasterling 2010

1
나는 그것들을 프로덕션 상태로 유지하고 그에 따라 내 오류 처리기를 조정합니다.
Daniel W.

3

아니요, 동료는이를 범용 오류 처리기로 사용해서는 안됩니다. 설명서에 따르면 :

어설 션은 디버깅 기능으로 만 사용해야합니다. 항상 TRUE 여야하는 조건을 테스트하고 그렇지 않은 경우 일부 프로그래밍 오류를 나타내는 온 전성 검사에 사용하거나 확장 기능이나 특정 시스템 제한 및 기능과 같은 특정 기능의 존재 여부를 확인할 수 있습니다.

입력 매개 변수 검사와 같은 일반적인 런타임 작업에는 어설 션을 사용하면 안됩니다. 일반적으로 어설 션 검사가 활성화되지 않은 경우 코드가 항상 올바르게 작동 할 수 있어야합니다.

자동화 된 테스트 스위트에 익숙한 경우 일반적으로 "assert"동사를 사용하여 일부 메서드 또는 기능의 출력을 확인합니다. 예를 들면 :

function add($a, $b) {
    return $a + $b;
}

assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');

동료는이를 범용 오류 처리기로 사용해서는 안되며이 경우 입력 확인으로 사용해서는 안됩니다. 라이브러리의 일부 사용자가 레코드 필드를 설정하지 않을 수있는 것 같습니다.


3

동료가 실제로 Eiffel 언어의 계약에 의한 설계 (DbC) 를 적용하려고 시도하고 있으며 책 : Object Oriented Software Construction, 2nd Edition을 기반으로합니다.

그가 사용한 주장은 Hoare Logic 또는 Hoare Triple의 {P} 부분이 될 것입니다. {P} C {Q}, 여기서 {P}는 전제 조건 주장 (이온)이고 {Q}는 다음과 같습니다. 사후 조건 주장 (이온).

버그가있는 PHP의 assert 기능에 대한 조언을 비판적으로 기록 할 것입니다. 버그가있는 코드를 사용하고 싶지 않습니다. 당신이 정말로 원하는 것은 PHP의 제작자가 assert의 버그를 고치는 것입니다. 그렇게 할 때까지 assert를 사용할 수 있지만 현재 버그가있는 상태를 염두에두고 사용하십시오.

또한 assert 기능에 버그가있는 경우 프로덕션 코드에서 사용하지 않는 것이 좋습니다. 그럼에도 불구하고 적절한 경우 개발 및 테스트 코드에서 사용하는 것이 좋습니다.

마지막으로 계약별로 디자인을 연구하면 객체 지향 고전적 상속에 비추어 부울 어설 션을 사용하는 데 결과가 있음을 알 수 있습니다. 즉, 전제 조건을 약화하거나 사후 조건을 약화해서는 안됩니다. 그렇게하면 서로 상호 작용하는 다형성 자손 객체에 위험 할 수 있습니다. 이것이 의미하는 바를 이해하기 전까지는 그대로 두겠습니다!

또한, PHP 제작자가 계약에 따라 포괄적 인 설계 연구를 수행하고 최대한 빨리 PHP에 적용 할 것을 강력히 권장합니다! 그러면 우리 모두는 DbC 인식 컴파일러 / 인터프리터를 사용하여 혜택을받을 수 있으며, 이는 답변 (위)에 명시된 문제를 처리합니다.

  1. 적절하게 구현 된 계약 별 설계 컴파일러는 (현재 PHP 어설 션과 달리) 버그가 없을 것입니다.
  2. 적절하게 구현 된 계약 별 설계 인식 컴파일러는 문제에 대해 두뇌를 쌓는 대신 다형성 주장 논리 관리의 뉘앙스를 처리합니다!

참고 : ifassert (전제 조건) 대신-문을 사용하는 경우에도 전제 조건을 강화하거나 사후 조건을 약화시키는 데 사용하면 심각한 결과를 초래할 수 있습니다. 그것이 의미하는 바를 이해하려면 계약으로 디자인을 공부해야 알 수 있습니다! :-)

즐거운 공부와 학습.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.