원형 수입은 오히려 힘들 수 있지만, 지속적으로 행동 할 수 . 결정적인 포인트는
use Some::Module
는
- 모듈이로드
BEGIN { require Some::Module; Some::Module->import }
처럼 동작, 그것은 컴파일 및 실행됩니다. BEGIN
블록이 주변 코드의 구문 분석 중에 실행됩니다.
- 각 모듈은
require
번만입니다. 다시 필요하면 require
은 입니다.이 무시됩니다.
네 개의 파일을 BEGIN 블록에 require
개의 파일이 포함 된 단일 파일로 결합 할 수 있습니다.
의 당신의 기본 파일 시작하자 :
use MyA;
use MyB;
MyB->new()->the_method();
우리는 use
BEGIN { require ... }
에 변환하고 MyA
내용을 포함 할 수 있습니다. 명확하게하기 위해이 경우에는 관련이 없으므로 MyA
및 MyB
에있는 모든 ->import
통화는 무시합니다.
BEGIN { # use MyA;
package MyA;
use Moo;
with ('MyRole');
sub the_method { die; }
}
BEGIN { # use MyB;
require MyB;
}
MyB->new()->the_method();
with('MyRole')
는 또한 우리가 명시 적으로 만들 수있는 require MyRole
, 수행합니다
BEGIN { # use MyA;
package MyA;
use Moo;
{ # require MyRole;
package MyRole;
use Moo::Role;
use MyB;
requires 'the_method';
before the_method => sub { die 'This has been correctly executed'; };
}
with ('MyRole');
sub the_method { die; }
}
BEGIN { # use MyB;
require MyB;
}
MyB->new()->the_method();
우리는 그 다음도 MYB의 with('MyRole')
을 확대 use MyB
을 확장 할 수 있습니다 :
...
require MyRole;
with('MyRole ');
은 그래서 그 확장하자를 require
:
BEGIN { # use MyA;
package MyA;
use Moo;
{ # require MyRole;
package MyRole;
use Moo::Role;
BEGIN { # use MyB;
package MyB;
use Moo;
require MyRole;
with ('MyRole');
sub the_method { die 'The code should have died before this point'; }
}
requires 'the_method';
before the_method => sub { die 'This has been correctly executed'; };
}
with ('MyRole');
sub the_method { die; }
}
BEGIN { # use MyB;
require MyB;
}
MyB->new()->the_method();
MyB
내에는 require MyRole
이 있지만이 모듈은 이미 필요합니다. 그러므로, 이것은 아무 것도하지 않습니다. 실행 중에 그 시점에서, MyRole
는이 구성
package MyRole;
use Moo::Role;
그래서 역할이 비어 있습니다. requires 'the_method'; before the_method => sub { ... }
은 아직 컴파일되지 않았습니다.
따라서 MyB
은 빈 역할을 구성하며 the_method
에 영향을주지 않습니다.
어떻게 피할 수 있습니까? 이 경우에는 use
을 피하는 것이 도움이됩니다. 왜냐하면 현재 모듈이 초기화되기 전에 구문 분석을 인터럽트하기 때문입니다. 이것은 직관적이지 못한 행동으로 이어집니다.
use
모듈이 클래스 일 뿐이고 소스 코드가 구문 분석되는 방식 (예 : 서브 루틴 가져 오기)에 영향을주지 않으면 실행 시간을 지연시킬 수 있습니다. 최상위 코드가 실행되는 모듈의 런타임뿐만 아니라 주 응용 프로그램의 런타임까지. 즉, require
을 가져온 클래스를 사용해야하는 서브 루틴에 고정해야합니다. require
에는 필요한 모듈이 이미 가져 왔을 때도 여전히 약간의 오버 헤드가 있기 때문에 state $require_once = require Some::Module
과 같은 요구 사항을 보호 할 수 있습니다. 그런 식으로, 요구에는 런타임 오버 헤드가 없습니다.
일반적으로 모듈의 최상위 코드에서 가능한 한 작은 초기화를 수행하면 많은 문제를 피할 수 있습니다. 게으른 것을 선호하고 그 초기화를 연기하십시오. 한편,이 게으름은 시스템을보다 역동적이고 예측하기 어렵게 만들 수 있습니다. 이미 초기화가 어떤 일이 발생했는지 알기는 어렵습니다.
더 일반적으로 디자인에 대해 열심히 생각하십시오. 이 순환 종속성이 필요한 이유는 무엇입니까? 상위 수준 코드가 하위 수준 코드에 종속 된 계층화 된 아키텍처를 고수하거나 낮은 수준 코드가 상위 수준 인터페이스에 종속되는 종속성 역변환을 사용하도록 결정해야합니다. 두 가지를 섞으면 끔찍한 혼란이 생길 것입니다 (전시 A :이 질문).
일부 데이터 모델에는 반드시 동시 재귀 클래스가 있습니다. 이 경우 상호 의존 클래스를 단일 파일에 배치하여 수동으로 순서를 정렬하는 것이 가장 명확 할 수 있습니다.