수정할 수없는 Perl 라이브러리에서 '다이'호출을 어떻게 얻을 수 있습니까?

StackOverflow https://stackoverflow.com/questions/451227

  •  19-08-2019
  •  | 
  •  

문제

예, 문제는 내가 사용하는 라이브러리에 관한 것이며, 수정할 수 없습니다. 해결 방법이 필요합니다.

기본적으로, 나는 잘못 쓰여진 PERL 라이브러리를 다루고 있습니다. 특정 오류 조건이 파일을 읽는 것이 발생하면 '다이'로 종료됩니다. 나는 수천 개의 파일을 통해 반복되는 프로그램 에서이 루틴을 부릅니다. 나쁜 파일이 발생합니다. 나는 단지 내 일상이 오류를 기록하고 계속 진행하기를 원합니다.

라이브러리를 수정할 수 있다면 간단히 변경합니다.

die "error";

a

print "error";return;

, 하지만 난 할 수 없어. 잘못된 파일이 전체 프로세스에 충돌하지 않도록 루틴을 소파 할 수있는 방법이 있습니까?

후속 질문 : "평가"를 사용하여 충돌이 발생하기 쉬운 통화를 잘 수행하지만 해당 프레임 워크 내에서 잡을 수있는 오류를 처리하는 방법을 어떻게 설정합니까? 설명하기:

라이브러리를 부르는 서열이 있습니다. 이 서브 루틴 안에있는 각 호출을 평가 {}로 소개하는 대신, 나는 단지 죽을 수있게하고, 내 서브 루틴이라고하는 레벨에서 Eval {}를 사용합니다.

my $status=eval{function($param);};
unless($status){print $@; next;}; # print error and go to next file if function() fails

그러나 function ()에서 잡을 수있는 오류 조건이 있습니다. 서브 루틴과 호출 루틴의 오류 캐칭을 설계하는 가장 적절한/우아한 방법은 무엇입니까?

도움이 되었습니까?

해결책

당신은 그것을 묶을 수 있습니다 eval. 보다:

perldoc -f eval

예를 들어, 당신은 다음을 쓸 수 있습니다.

# warn if routine calls die
eval { routine_might_die }; warn $@ if $@;

이것은 치명적인 오류를 경고로 바꿀 것입니다. 만약에 die 호출됩니다. $@ 전달 된 문자열이 포함되어 있습니다.

다른 팁

트랩을합니까? $SIG{__DIE__}? 그것이 그렇다면, 그것은 당신보다 더 지역적입니다. 그러나 몇 가지 전략이 있습니다.

  • 패키지를 불러 일으킬 수 있습니다 우세하다 주사위:

    package Library::Dumb::Dyer;
    use subs 'die';
    sub die {
        my ( $package, $file, $line ) = caller();
        unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) {
            say "It's a good death.";
            die @_;
       }
    } 
    
  • 그렇지 않다면 할 수 있습니다 그것. (페이지에서 $ sig를 찾으십시오. Markdown은 전체 링크를 처리하지 않습니다.)

    my $old_die_handler = $SIG{__DIE__};
    sub _death_handler { 
        my ( $package, $file, $line ) = caller();
        unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) {
            say "It's a good death.";
            goto &$old_die_handler;
        }
    }
    $SIG{__DIE__} = \&_death_handler;
    
  • 라이브러리를 스캔하고 서브를 찾아야 할 수도 있습니다. 언제나 전화를 걸고 그것을로드하는 데 사용하십시오 $SIG 재정의하여 핸들러 that.

    my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb;
    *Dumb::do_something_dumb = sub { 
        $SIG{__DIE__} = ...
        goto &$dumb_package_do_something_dumb;
    };
    
  • 또는 그 내장을 무시하십시오 언제나 전화 ...

    package Dumb; 
    use subs 'chdir';
    sub chdir { 
        $SIG{__DIE__} = ...
        CORE::chdir @_;
    };
    
  • 다른 모든 것이 실패하면, 당신은 이것으로 말의 눈을 채울 수 있습니다.

    package CORE::GLOBAL;
    use subs 'die';
    
    sub die { 
        ... 
        CORE::die @_;
    }
    

이것은 무시할 것입니다 주사위 전 세계적으로, 당신이 돌아올 수있는 유일한 방법입니다 die 그것을 다루는 것입니다 CORE::die.

이것의 일부 조합은 효과가 있습니다.

a를 바꾸더라도 die 죽지 않으려면 다른 답변과 같이 특정 솔루션이 있습니다. 일반적으로 다른 패키지에서 서브 루틴을 항상 무시할 수 있습니다. 원래 소스를 전혀 변경하지 않습니다.

먼저 원래 패키지를로드하여 모든 원본 정의를 얻을 수 있습니다. 원본이 설치되면 번거로운 서브 루틴을 재정의 할 수 있습니다.

 BEGIN {
      use Original::Lib;

      no warnings 'redefine';

      sub Original::Lib::some_sub { ... }
      }

원래 정의를 자르고 붙여 넣고 필요한 것을 조정할 수도 있습니다. 훌륭한 솔루션은 아니지만 원본 소스를 변경할 수 없거나 원본을 변경하기 전에 무언가를 시도하려면 작동 할 수 있습니다.

게다가 원래 소스 파일을 응용 프로그램의 별도 디렉토리에 복사 할 수 있습니다. 해당 디렉토리를 제어하므로 파일을 편집 할 수 있습니다. Perl의 모듈 검색 경로에 해당 디렉토리를 추가하여 해당 사본을 수정하고로드합니다.

use lib qw(/that/new/directory);
use Original::Lib;  # should find the one in /that/new/directory

누군가가 원래 모듈을 업데이트하더라도 사본이 고정됩니다 (변경 사항을 병합해야 할 수도 있음).

나는 이것에 대해 조금 이야기합니다 마스터 링 Perl, 나는 그런 종류의 일을하는 다른 기술을 보여줍니다. 속임수는 더 많은 것을 깨지 않는 것입니다. 당신이 일을 깨지 않는 방법은 당신이하고있는 일에 달려 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top