Menu
Coddy logo textTech

트레이트 충돌 해결

Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 91개 중 53번째.

두 개의 트레이트(trait)가 동일한 이름의 메서드를 정의하면, PHP는 치명적 오류(fatal error)를 발생시킵니다. insteadofas 연산자를 사용하여 이 충돌을 처리하는 방법을 PHP에 명시적으로 알려주어야 합니다.

<?php
trait FileLogger {
    public function log(string $message): void {
        echo "File: $message";
    }
}

trait DatabaseLogger {
    public function log(string $message): void {
        echo "DB: $message";
    }
}

class Application {
    use FileLogger, DatabaseLogger {
        FileLogger::log insteadof DatabaseLogger;
        DatabaseLogger::log as logToDatabase;
    }
}

$app = new Application();
$app->log("Error occurred");
$app->logToDatabase("Error occurred");

출력:

File: Error occurred
DB: Error occurred

insteadof 연산자는 충돌이 발생했을 때 어떤 트레이트(trait)의 메서드를 사용할지 선택합니다. 이 예제에서는 FileLogger::log가 우선권을 가지며 기본 log() 메서드가 됩니다. as 연산자는 별칭(alias)을 생성하여, 다른 트레이트의 메서드를 다른 이름으로 접근할 수 있게 해줍니다.

또한 as를 사용하여 메서드의 가시성을 변경할 수 있습니다:

<?php
trait Greeting {
    public function sayHello(): void {
        echo "Hello!";
    }
}

class Person {
    use Greeting {
        sayHello as private;
    }
}

이것은 sayHello()가 trait에서는 public임에도 불구하고, Person 클래스 내에서 private이 되도록 만듭니다. 충돌 해결(Conflict resolution)을 통해 trait 메서드가 클래스에 통합되는 방식을 세밀하게 제어할 수 있습니다.

challenge icon

챌린지

쉬움

여러 트레이트(trait)가 동일한 메서드 이름을 제공할 때 발생하는 충돌을 해결하면서, 다양한 채널을 통해 메시지를 보낼 수 있는 알림 시스템을 구축해 보겠습니다.

코드는 다음 네 개의 파일로 구성됩니다:

  • EmailNotifier.php"Email: [message]"를 반환하는 notify(string $message) 메서드를 가진 EmailNotifier 트레이트를 생성합니다.
  • SmsNotifier.php"SMS: [message]"를 반환하는 notify(string $message) 메서드를 가진 SmsNotifier 트레이트를 생성합니다.
  • AlertService.php — 두 트레이트를 모두 사용하는 AlertService 클래스를 생성합니다. 두 트레이트 모두 notify() 메서드를 가지고 있으므로, 다음과 같이 충돌을 해결해야 합니다:
    • EmailNotifier::notify를 기본 notify() 메서드로 사용합니다.
    • SmsNotifier::notify 메서드에 대해 notifyBySms라는 별칭(alias)을 생성합니다.
    또한 두 알림 메서드를 모두 호출하고 그 결과를 각각 별도의 줄에 결합하여 반환하는 notifyAll(string $message) 메서드를 추가합니다.
  • main.php — 필요한 모든 파일을 포함하고 AlertService 인스턴스를 생성합니다. 하나의 입력값으로 메시지 문자열을 받습니다. 다음 세 줄을 출력합니다:
    • 메시지와 함께 notify()를 호출한 결과
    • 메시지와 함께 notifyBySms()를 호출한 결과
    • 메시지와 함께 notifyAll()을 호출한 결과

이 과정은 이름 충돌이 발생했을 때 insteadof를 사용하여 어떤 트레이트의 메서드를 우선할지 결정하고, as를 사용하여 다른 트레이트의 메서드를 다른 이름으로 계속 사용할 수 있는 방법을 보여줍니다.

치트 시트

여러 트레이트(trait)가 동일한 이름의 메서드를 정의할 때, PHP는 insteadofas 연산자를 사용한 명시적인 충돌 해결을 요구합니다.

insteadof 연산자는 어떤 트레이트의 메서드를 기본으로 사용할지 선택합니다:

<?php
trait FileLogger {
    public function log(string $message): void {
        echo "File: $message";
    }
}

trait DatabaseLogger {
    public function log(string $message): void {
        echo "DB: $message";
    }
}

class Application {
    use FileLogger, DatabaseLogger {
        FileLogger::log insteadof DatabaseLogger;
        DatabaseLogger::log as logToDatabase;
    }
}

$app = new Application();
$app->log("Error occurred"); // File: Error occurred
$app->logToDatabase("Error occurred"); // DB: Error occurred

as 연산자는 트레이트 메서드에 대한 별칭(alias)을 생성하여, 다른 이름으로 접근할 수 있게 해줍니다.

또한 as를 사용하여 메서드의 가시성(visibility)을 변경할 수 있습니다:

<?php
trait Greeting {
    public function sayHello(): void {
        echo "Hello!";
    }
}

class Person {
    use Greeting {
        sayHello as private;
    }
}

직접 해보기

<?php
require_once 'AlertService.php';

// 입력 읽기
$message = trim(fgets(STDIN));

// TODO: AlertService 인스턴스 생성

// TODO: 메시지와 함께 notify()를 호출한 결과 출력

// TODO: 메시지와 함께 notifyBySms()를 호출한 결과 출력

// TODO: 메시지와 함께 notifyAll()을 호출한 결과 출력
?>
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨