트레이트 – 12.충돌 방지 연산자

트레이트는 이미 다른 프로그래밍 언어에서 사용되며 충돌이 발생할 수 있다는 것을 보여 주었지만 이것은 정해진 방식(rule)이라기 보다는 예외적인 상황(exception)입니다. 대부분의 시스템에서 충돌 방지(conflict resolution)를 위한 메커니즘은 자주 사용되는 것은 아니지만 개발자의 구성 능력을 높일 수 있는 중요한 메커니즘으로 입증되었습니다. 일반적인 충돌의 한 예는 다른 트레이트가 동일한 이름의 메소드를 제공하는 경우입니다.

두 트레이트 모두 Talker라는 클래스에서 사용되어야 합니다. 다중 상속(multiple inheritance)과 믹스인(Mixin)은 이 충돌을 방지하기 위한 알고리즘을 정의하고 있습니다. 트레이트는 그렇지 않습니다. 충돌은 어떤 종류의 우선 순위로도 암시적으로 해결되지 않습니다. 대신, 암시적 복잡성을 피하기 위해 개발자가 충돌하는 메소드 중의 하나를 선택하도록 클래스를 구성할 수 있습니다. 개발자가 클래스 구성에 관한 완전한 통제 권한을 가지고 있습니다.

위의 Talker 정의의 경우, smallTalk와 bigTalk 메소드의 이름이 충돌했기 때문에 PHP는 치명적인 오류(Fatal error)로 컴파일을 중단합니다.

insteadof 연산자

동일한 이름의 메소드를 가진 두 개의 트레이트가 조합되었을 때, 나타나는 충돌을 명시적으로 해결하지 않는 이상 치명적인 오류(Fatal error)가 발생합니다. 동일한 클래스에서 조합된 트레이트 간의 메소드 이름 충돌을 방지하지 위해 개발자는 충돌하는 메소드 중에 어떤 메소드를 사용해야 하는지 하나를 분명하게 선택하기 위하여 insteadof 연산자를 사용할 필요가 있습니다.

Talker는 A와 B에는 충돌하는 smallTalk와 bigTalk 메소드가 있으므로, 트레이트 B의 smallTalk 메소드와 트레이트 A의 bigTalk 메소드를 사용하도록 정의합니다. 이에 따라 특성 A의 smallTalk 메소드와 특성 B의 bigTalk 메소드가 제거되어 사용할 수 없게 됩니다.

따라서 클래스 Talker는 smallTalk 메소드에 대해 ‘b’를, bigTalk 메소드에 대해 ‘A’를 선택합니다. 그러나 이와 같이 insteadof 연산자를 이용한 단순한 형태의 메소드 제외가 모든 상황에 맞는 가장 적합한 선택은 아닙니다. 왜냐하면 이렇게 하면 다른 메소드를 제외한 하나의 메소드만 허용하기 때문입니다.

as 연산자

메소드를 제외하는 방식 외에도 트레이트의 메소드에 새 이름을 부여할 수 있습니다. 이와 같이 트레이트 메소드 원래의 메소드 이름 대신에 새 이름을 부여하게 되면, 새 이름으로 원래의 메소드가 수행됩니다. 제외된 다른 메소드 중의 하나를 사용하기 위해서는 as 연산자를 사용하여 별칭을 부여합니다.

아래 예에서는 Talker 클래스에서 B::bigTalk 메소드를 새 이름 talk로 수행하도록 하려고 합니다. as 연산자는 트레이트 원래의 메소드의 이름을 바꾸지 않으며 대신 트레이트 원래의 메소드에 talk라는 이름이 추가적으로 부여함으로 다른 메소드에도 영향을 주지 않습니다.

Aliased_Talker는 as 연산자를 사용하여 별칭 talk를 부여함으로 B 트레이트의 bigTalk 메소드를 호출하도록 만듭니다. talk 내부의 재귀 호출은 여전히 B 트레이트에 있는 bigTalk라는 이름의 메소드를 호출합니다.

결과적으로 A, B 트레이트가 Talker 클래스에 조합(insert)된 후에는, Talker 클래스는 다음 세 가지 메소드로 구성됩니다.

talk 메소드는 새 이름이 추가된 메소드로 인식되기 때문에 B 트레이트에 있는 bigTalk 메소드는 여전히 제외해야 합니다. 그렇지 않으면 PHP는 트레이트의 두 메소드가 충돌하여 치명적인 오류(Fatal error)가 발생합니다. 새 이름을 부여한다고 기존의 이름이 변경되지 않으며, 지정된 메소드 이름에 대한 메소드의 참조도 변경되지 않습니다. 처음에는 이상하게 들릴지 모르지만, 그것은 매우 원활한 트레이트들의 조합 뿐만 아니라 트레이트의 계층 구조까지도 구축할 수 있는 기회를 제공합니다.

답글 남기기