PHP는 friend 또는 internal 접근 제어를 지원할까?
결론부터 말씀드리면, PHP는 C++의 friend나 C#의 internal처럼 특정 클래스에 한해 private 멤버 접근을 허용하는 선언을 공식적으로 지원하지 않습니다. 언어 차원에서 이러한 세밀한 접근 제어 문법이 없기 때문에, 개발자는 다른 우회 방법을 찾아야 합니다.
__get과 __set 매직 메서드로 friend 흉내 내기
PHP 5 이상에서는 __get()과 __set() 매직 메서드를 활용하고, debug_backtrace() 함수로 호출자의 클래스를 검사하는 방식으로 friend와 유사한 동작을 흉내 낼 수 있습니다. 아래 예제 코드를 살펴보겠습니다.
class sample_friend {
private $__friends = array('My_Friend', 'Other_Friend');
public function __get($key) {
$trace = debug_backtrace();
if(isset($trace[1]['class']) && in_array($trace[1]['class'], $this->__friends)) {
return $this->$key;
}
// 일반적인 __get() 처리 코드
trigger_error('Cannot access private property ' . __CLASS__ . '::$' . $key, E_USER_ERROR);
}
public function __set($key, $value) {
$trace = debug_backtrace();
if(isset($trace[1]['class']) && in_array($trace[1]['class'], $this->__friends)) {
return $this->$key = $value;
}
// 일반적인 __set() 처리 코드
trigger_error('Cannot access private property ' . __CLASS__ . '::$' . $key, E_USER_ERROR);
}
}
동작 원리
- 허용할 클래스 이름을
$__friends배열에 미리 정의해 둡니다. - 외부에서 private 프로퍼티에 접근하려 하면 PHP가 자동으로
__get()또는__set()을 호출합니다. debug_backtrace()로 호출 스택을 확인하여, 실제 호출한 클래스가 허용 목록($__friends)에 있는지 검사합니다.- 허용된 클래스라면 프로퍼티 접근을 그대로 반환하고, 그렇지 않으면
trigger_error()로 치명적 오류를 발생시켜 접근을 차단합니다.
주의할 점
이 방식은 동작은 하지만, 실무에서는 서투르고(clumsy) 권장되지 않는 코딩 관행으로 여겨집니다. 그 이유는 다음과 같습니다.
debug_backtrace()호출은 성능 오버헤드가 상당히 큽니다.- friend 목록이 문자열로 하드코딩되어 유지보수가 어렵고, 클래스 리팩터링 시 깨지기 쉽습니다.
- 코드의 의도가 명확하게 드러나지 않아 가독성이 떨어집니다.
따라서 실제 프로젝트에서는 이런 트릭보다는 인터페이스 설계, 컴포지션(위임), 팩토리 패턴 등 객체지향 원칙에 맞는 구조로 문제를 해결하는 것이 바람직합니다.