로그인 회원가입
모두인포
전체IT경제사회생활스포츠시사여행연애

PHP의 접근 제어자(access modifier)

lmkfox · 2025-08-28 · 조회 0
PHP의 접근 제어자(access modifier)
1. 개요 접근 제어자는 클래스 내부 멤버(프로퍼티·메소드·상수)가 어디에서 접근 가능한지를 결정합니다. 주로 세 가지가 있습니다. - public : 어디서든 접근 가능 (클래스 내부, 자식, 외부 코드) - protected : 클래스 자신과 자식 클래스에서만 접근 가능 - private : 해당 클래스 내부에서만 접근 가능 (자식도 접근 불가) (참고) final, abstract, static, readonly 등은 접근 제어자와 별개입니다. readonly는 가시성은 아니고 쓰기 금지 속성입니다(PHP 8.1+). 2. 적용 대상 - 프로퍼티(property) : 인스턴스 변수(또는 static) 선언 시 가시성 사용 - 메소드(method) : 인스턴스/정적 메소드 가시성 - 클래스 상수(const) : PHP 7.1부터 가시성(public/protected/private) 선언 가능 3. 기본 문법 예제 <?php class A { public int $pub = 1; protected int $prot = 2; private int $priv = 3; public function publicMethod() { return $this->priv; } // OK protected function protectedMethod() { return $this->prot; } // 내부/자식용 private function privateMethod() { return $this->priv; } // 오직 이 클래스 내부 } $a = new A(); echo $a->pub; // OK // echo $a->prot; // 오류: protected 접근 불가 // echo $a->priv; // 오류: private 접근 불가 4. 상속(override) 규칙 - 오버라이드 시 접근성: 부모 메소드보다 더 제한적(더 숨김) 으로 바꿀 수 없습니다. 즉, - 부모가 public이면 자식은 public만 가능(더 좁힐 수 없음). - 부모가 protected이면 자식은 protected 또는 public으로 바꿀 수 있습니다(더 넓힐 수는 있음). - 이유: Liskov Substitution Principle(리스코프 치환 원칙) — 서브타입은 슈퍼타입으로 대체 가능해야 합니다. 예: class Base { public function foo() {} } class ChildBad extends Base { // public -> protected 로 변경하면 fatal error: access level must be public // protected function foo() {} // 오류 } 5.  private 의 특성 —  클래스 단독 범위 - private 프로퍼티/메소드는 정의된 클래스 내부에서만 접근 가능. 같은 명칭의 private 멤버를 부모/자식 클래스가 각각 선언하면 서로 다른 멤버로 취급됩니다(완전 분리). - 때문에 부모 클래스의 private 메소드나 프로퍼티는 자식에서 덮어써도 부모의 것을 가리키지 않습니다. 6. static 멤버와 가시성 - public static, protected static, private static 동일하게 작동. - 접근: ClassName::$prop 또는 self::$prop, static::$prop 등으로 접근. - self::은 정의된 클래스의 멤버를 가리키고, static::(늦은 정적 바인딩)은 호출한 클래스를 가리킵니다. 가시성은 동일 규칙 적용. 7. 클래스 상수의 가시성 (PHP 7.1+) class X { public const PUBLIC_C = 'pub'; protected const PROT_C = 'prot'; private const PRIV_C = 'priv'; } - public 상수는 클래스 외부에서 X::PUBLIC_C로 접근 가능. - protected/private 상수는 그 가시성 규칙대로 제한됩니다. 8. 인터페이스와 트레이트 관련 - 인터페이스: 메소드는 항상 public입니다. (인터페이스에 protected/private 메소드는 선언할 수 없습니다.) - 트레이트: 트레이트에 선언된 멤버도 가시성을 가질 수 있으며, 클래스로 use할 때 insteadof, as로 충돌 해결 및 가시성 변경(별칭) 가능: trait T { protected function tMethod() {} } class C { use T { tMethod as public; // 가시성 변경 예 } } 9. 생성자와 가시성의 실무적 사용 - 생성자를 private로 선언하면 외부에서 new로 만들 수 없고 정적 팩토리를 통해 인스턴스 생성 제어 가능: class OnlyFactory { private function __construct() {} public static function create(): self { return new self(); } } 10. Closure / 바인딩과 스코프 - Closure::bind 또는 $closure->call($obj)를 사용하면 클로저의 실행 스코프를 바꿔 private/protected 멤버에 접근할 수 있도록 할 수 있습니다(강력하지만 남용 위험). - 예: Closure::bind(function(){ return $this->priv; }, $obj, $obj::class) — 객체의 private에 접근 가능. 11. 마법 메소드( __get ,  __set )와 가시성 우회 - 선언되지 않은(또는 접근 불가) 프로퍼티 접근 시 __get/__set이 호출되므로 외부에서 private 멤버 접근을 흉내낼 수 있으나 이는 캡슐화 규칙을 우회하는 것이므로 신중히 사용. 12. 흔한 실수와 주의사항 - public 프로퍼티를 남발하면 캡슐화·불변성·검증 책임이 깨집니다. 가능한 private + 게터/메소드 사용 권장. - 부모의 private 멤버를 자식에서 동일 이름으로 사용하면 “덮어쓴다”기보다 서로 다른 멤버가 됩니다 — 혼동 주의. - 생성자에서 오버라이드 가능한 메소드 호출(즉, 자식에서 재정의된 메소드 호출)은 위험. 자식 필드 초기화가 끝나기 전에 자식 메소드가 호출되어 부분 상태를 다룰 수 있음. - protected는 테스트/확장을 위해 유용하지만 남용 시 구현 세부 사항 노출(캡슐화 파손)로 이어질 수 있음. 가능한 private + 공용 API 권장. 13. 디버깅 팁 - 접근 오류(예: Cannot access protected property)가 나오면 호출 위치를 먼저 확인 — 클래스 외부인지, 자식인지, 같은 클래스인지 확인. - 리플렉션(Reflection)으로 접근 가능성 확인 가능(단, Reflection API 사용은 고급 디버깅/툴 용도). 14. 실무 권장 관행(요약) - 프로퍼티는 기본 private. 필요한 경우에만 protected/public 사용. - 외부 접근은 명확한 게터/메소드로 제공(검증/불변성 유지). - 상속 API(자식이 사용할 것)는 protected로 설계하고 명확히 문서화. - 불변 값은 readonly(PHP 8.1+)로 표현. - 팩토리/DI를 활용하여 생성자 가시성(예: private 생성자 + static factory)로 인스턴스화 제어. 15. 실습 예제 모음 <?php class ParentClass { private function secret() { return "parent secret"; } protected function doProtected() { return "ok"; } public function publicAPI() { return $this->doProtected(); } } class ChildClass extends ParentClass { // secret()는 부모의 private라서 여기서 다시 정의해도 부모 것과 분리된다 private function secret() { return "child secret"; } // 부모 protected 메소드를 공개로 확장(허용) public function doProtected() { return "child override"; } public function show() { // 부모의 private secret() 접근 불가: $this->secret() 호출 시 ChildClass의 secret() 호출 return $this->secret(); } } $c = new ChildClass(); echo $c->publicAPI(); // "child override" echo $c->show(); // "child secret" 마무리 요약 - public / protected / private는 클래스 설계의 핵심 도구입니다. - 원칙: 멤버는 가능한 한 더 좁은 범위(private) 로 만들고, 외부와의 계약은 메소드(혹은 readonly 게터)로 노출하세요. - 상속·트레이트·팩토리 패턴과 결합해 올바른 캡슐화와 확장성을 확보하는 것이 중요합니다.

댓글

아직 댓글이 없습니다.

로그인 후 댓글을 남길 수 있습니다.