마 젠토에서 중성 타입 힌트 다루기


15

Magento의 사용자 정의 오류 처리기와 공존하는 유형 검사에 대해 생각했던 것보다 더 나은 전략이 있는지 궁금합니다. 특히, typehinted 매개 변수가 일치하지 않는 경우 "캐치 가능한 치명적 오류"에 대해 궁금합니다. 다음은 Mage수업 의 예입니다 .

/**
 * Write exception to log
 *
 * @param Exception $e
 */
public static function logException(Exception $e)
{
    if (!self::getConfig()) {
        return;
    }
    $file = self::getStoreConfig('dev/log/exception_file');
    self::log("\n" . $e->__toString(), Zend_Log::ERR, $file);
}

오류 처리기 때문에 Zend_Date(잘 작동하지만 예외 로그에서 매우 혼란스럽게 보임) 또는 Mage_Core_Model_App실제로 치명적인 오류가있는를 포함하여 무엇이든 메소드에 전달할 수 있습니다 .

메소드 맨 위에서 타입 검사를 다시 구현할 수는 $e instanceof Exception있지만 이러한 전술은 타이핑 힌트의 목적을 무너 뜨립니다.

어떤 힌트 제안?

답변:


5

좋은 질문 +1

첫 번째 답변에서 @mpw와의 토론 후 지시에 좋은 지적을 한 후 몇 가지 연구와 테스트를 수행했습니다. 나는 처음으로 그것을 오해했다.

다른 사람들이 문제를 더 잘 이해하도록 명확한 코드를 추가합니다.

이륙 전 메모

이것이 일어날 때까지 나는 그런 문제가 없었습니다. 개발자 모드를 사용하여 Magento에서 개발하기 나는 이것에 대해 잠시 생각조차하지 않습니다. 그래서 내가 방귀 때마다 표시되고 그에 따라 수정됩니다.

설명하는 샘플의 문제점

치명적인 오류가 기록되고 (활성화 된 경우) 오류가 발생하지 mageCoreErrorHandler않거나 프로그램에서 오류가 발생하여 평소와 같이 코드가 계속 진행 됩니다 exit.

잡을 수없는 오류에 대한 첫 마젠 토의 핵심 오류 처리기 app/code/core/Mage/Core/functions.php

/**
 * Custom error handler
 *
 * @param integer $errno
 * @param string $errstr
 * @param string $errfile
 * @param integer $errline
 */
function mageCoreErrorHandler($errno, $errstr, $errfile, $errline){
    /**
     * Some internal logic here for building the error message
     */

    $errorMessage .= ": {$errstr}  in {$errfile} on line {$errline}";
    if (Mage::getIsDeveloperMode()) {
        throw new Exception($errorMessage);
    } else {
        Mage::log($errorMessage, Zend_Log::ERR);
    }
}

보시다시피 개발자 모드에서는 유용한 정보를 알려 주면 오류가 발생합니다. 끄면 기록 (활성화 된 경우)되고 계속됩니다.

증거

나의 testfile.php

require 'app/Mage.php';
Mage::app('admin')->setUseSessionInUrl(false);

// Test function which expect Customer_Model_Customer
function test(Customer_Model_Customer $customer)
{
    var_dump('Do not show me because ' . get_class($customer) . ' is not a customer.');
}

// Enabled developer mode
Mage::setIsDeveloperMode(true);

// Put a var in here
$noGood = Mage::app();

// Make some context
var_dump('hello');
try {
    // Call test function with a not accepted var
    test($noGood);

    // Tell if we get here
    var_dump('And we are here!');

} catch (Exception $e) {
    var_dump('You should die, because I am doing something which I should not do');
}

결과

개발자 모드가 활성화되었습니다. 올바른 결과

string(5) "hello"
string(66) "You should die, because I am doing something which I should not do"

개발자 모드 비활성화, 잘못된 결과

string(5) "hello"
string(61) "Do not show me because Mage_Core_Model_App is not a customer."
string(16) "And we are here!"

따라서 결국 오류를 건너 뛰고 다음 코드 줄에서 계속합니다. 아마도 더 이상한 결과가 나올 수도 있습니다. (@mpw가 지적했듯이)

결론

그것은 수있는 누군가가 오류가 갈 것이다하는 방식으로 개발 일어날 주목 하고이 됩니다 결국 예기치 않은 결과를 제공합니다.

전문적인 방법으로 개발할 때 물론입니다. 오류는 것입니다 발견하고 주의를 지불하고 살만한있다. Magento에서이를 방지하는 방법은 개발자 / 테스트 환경에서 항상 개발자 모드를 활성화하는 것입니다.

IMHO 그것은이 논의의 지점에 도달해서는 안됩니다. 변수를 두 번 확인하는 것이 (적어도 그것이 내가 설명하는 방법입니다)가는 길입니다. 프로덕션 환경에서 릴리스하기 전에 코드를 테스트해야합니다. 그것은해야 하지 필요하다.

두번째 생각

치명적인 오류가 발생한 후 Magento가 중지 될 수 있습니다. 또는 보고서를 작성하여 방문자에게 보여주십시오. 이런 식으로 다음 줄의 코드는 절대 실행되지 않으며 상황이 감지됩니다.


> 전문적인 방법으로 개발할 때 거친 것. 오류가 발견되고주의를 기울입니다. Magento에서이를 방지하는 방법은 개발자 / 테스트 환경에서 항상 개발자 모드를 활성화하는 것입니다. ¶ 나는 동의합니다. 내 목표는 프로덕션 모드에서 Magento가 언어 규칙을 준수하는 것입니다. 아마도 맞춤 모듈이 필요할 것 같습니다. 통찰력 주셔서 감사합니다!
mpw

두 경우 모두 Magento가 예외를 throw해야 할 수도 있습니다. 사용자에게 Magento 오류 로그 페이지가 표시되며 var / exception에는 일반 예외와 동일한 로그 파일이 있습니다. 여기서 주목할 점은 코드가 예고없이 실행되지 않는다는 것입니다. 함수 파일을 앱 / 코드 / 로컬로 복사하고 항상 예외를 던질 수 있습니다.
Jeroen

1
나는 이것을 대답으로 표시하기로 결정했습니다. 그래도 머플 링 오류는 여전히 위험하다고 생각하지만 Magento가 다른 문제를 일으키지 않고 타이핑을 존중할 수있는 방법은 없을 것 같습니다. dev 모드를
켜두

2

좋은 질문. E_RECOVERABLE_ERRORPHP에서 일반적인 문제라고 생각합니다 .

귀하의 질문에있는 것은 오류 처리기가 아닌 예외 처리기입니다. 오류 처리기와 여기에 논의 실제 문제를 일으키는 잡을 치명적인 오류 ( E_RECOVERABLE_ERROR) .

PHP 7과 HHVM은 이미 해결되었습니다.

PHP 5.2 오류 클래스 이후로 오류 처리기가이 문제를 처리하지 않기 때문에 Magento가 더 나쁩니다.

보다 유용한 종류의 오류 처리는이 오류 클래스를 처리하고 이러한 오류를 ErrorException 으로 바꾸는 것 입니다. 예 (나가 아니라 여기에서 ) :

set_error_handler(function($errno, $errstr, $errfile, $errline) {
    if ($errno === E_RECOVERABLE_ERROR) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    return false;
});

따라서 Magento에 비추어 볼 때 기본 오류 처리기는의 전역 함수 mageCoreErrorHandler입니다 app/code/core/Mage/Core/functions.php. 그것은에 의해 등록의 수 Mage::app()에 의해 init()의 방법 Mage_Core_Model_App ( app/code/core/Mage/Core/Model/App.php(보호를 통해) _initEnvironment()방법).

PHP 오류 처리기를 맨 위에 등록 하는 관찰자controller_front_init_before 는 충분해야합니다 (PHP의 오류 처리기는 스택 가능).

$previous = set_error_handler(function($errno, $errstr, $errfile, $errline) use (&$previous) {
    if ($errno === E_RECOVERABLE_ERROR) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    if ($previous) {
        return call_user_func($previous, $errno, $errstr, $errfile, $errline);
    }
    return false;
});

잡을 치명적인 오류는 다음 예외로 켜져 있고 당신은 당신의 자신의 확장 코드에서 처리 할 수 또는 그들이 포착되지 않은 있습니다 대신 현재 동작이처럼 잘못된 유형에 대한 당신의 상점 실행 가가있는의 (예외 로그에 표시됩니다 죽은 프로그램 거짓말하지 마십시오 ). PHP 7 찾을 수있는 예외가 아니다 ErrorException 다음하지만 TypeException (A입니다 BaseException 지금의 경우) 잡을 치명적인 오류 .

다른 모든 오류는 Magento의 오류 처리기로 전달됩니다.

참고 : 나는 이것을 시도하지 않았지만, 그것은 기록이지만 당신이 묻는 문제를 알고 있으며 오류 처리 분석은 1.5.1.0에 대해 수행되었으며 코드 분석을 통해 1.9.1.0에 대해 검증되었습니다. 오류 처리기 스태킹이 작동해야합니다. 대부분의 부분이 작동하는 것을 보여주는 약간의 확장 된 예제 코드를 추가합니다.

나는 이것을 magento 확장으로 아직 패키지하지 않았지만 modman을 사용하여 간단해야합니다. 그런 다음 github에 넣겠습니다.

부록 : 오류 처리기 데모

다음 코드 예제 ( 온라인 데모 )는 오류 처리기의 스택 및 캐치 가능한 치명적 오류 에 대한 예외 발생을 보여줍니다 .

<?php
/**
 * error handler demonstration
 *
 * stackable error handle with previous call and catchable error exceptions
 *
 * @author hakre <http://hakre.wordpress.com>
 * @link /magento//a/64972/4115
 */

set_error_handler(function() {
    $args = func_get_args();
    var_dump("me is the previous error handler", $args);
});

$previous = set_error_handler(function($errno, $errstr, $errfile, $errline) use (&$previous) {
    if ($errno === E_RECOVERABLE_ERROR) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }
    if ($previous) {
        return call_user_func($previous, $errno, $errstr, $errfile, $errline);
    }
    return false;
});

$test = function(callable $test) {};

$a = $undefined; // provoke little warning

$test(new stdClass); // provoke catchable fatal error

프로그램 출력

string(32) "me is the previous error handler"
array(4) {
  [0]=>
  int(8)
  [1]=>
  string(29) "Undefined variable: undefined"
  [2]=>
  string(45) "/tmp/execpad-0eca072b619d/source-0eca072b619d"
  [3]=>
  int(28)
}

Fatal error: Uncaught exception 'ErrorException' with message 'Argument 1 passed to {closure}() must be callable, object given, called in /tmp/execpad-0eca072b619d/source-0eca072b619d on line 30 and defined' in /tmp/execpad-0eca072b619d/source-0eca072b619d:26
Stack trace:
#0 /tmp/execpad-0eca072b619d/source-0eca072b619d(26): {closure}(4096, 'Argument 1 pass...', '/tmp/execpad-0e...', 26, Array)
#1 /tmp/execpad-0eca072b619d/source-0eca072b619d(30): {closure}(Object(stdClass))
#2 {main}
  thrown in /tmp/execpad-0eca072b619d/source-0eca072b619d on line 26

뛰어난 쓰기. 테스트 중에 오류 처리기를 재설정하여 측정 가능한 성능 저하가 있었습니까?
mpw

나는 지금까지하지 않았습니다. 개발 모드에 모든 경고가 / 오류로 변환 코어 관련 지역도있다 예외 (그리고 ErrorExceptuion가 -도 기록하지 않음). 이 문제를 해결하려면 패치 세트가 필요할 수 있습니다. 오류 처리기에는 사용할 수있는 적절한 디스패치 방법이 없으며 여기서는 고정 된 기본 오류 처리기를 가져 오기 위해 코어를 패치하는 경향이 있습니다.
hakre

1

(Exception $e)함수 매개 변수 정의를 추가하여 기본 PHP에서 이미 처리했습니다 .

예외 또는 예외 확장 이외의 다른 기능은이 함수에 전달할 수 없습니다.


mageCoreErrorHandler기능을 살펴보십시오 . 잘못된 매개 변수로 트리거 된 오류는 개발자가 아닌 모드에서 처리 및 억제되며 개발자 모드 Exception에서 발생합니다.
mpw

처음에 그러한 일이 발생하면 심각한 문제가 있습니다. 마 젠토는 mageCoreErrorHandler방문자가 자신의 얼굴에 오류가 발생하지 않도록해야합니다. 당신은 try{}catch(){}그들 자신을 잡을 수 있는 자신 을 만들 수 있으며, 당신이 그들을 전달할 수없는 경우.
Jeroen

캐치 가능한 치명적 오류가 억제되는 경우 예외가 발생하지 않는다는 것을 고려하면 try / catch는 무엇을 얻습니까?
mpw

1
로컬 테스트를 마친 후에 마침내 그것을 얻었습니다 ... 당신이 맞습니다. 오류가 억제되고 코드가 계속됩니다. 답변을 업데이트하고 추가로 생각을 추가하겠습니다
Jeroen

그렇지 않으면 우리의 대화가 전혀 이해가되지 않습니다
Jeroen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.