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

PHP 상속 오버라이드(override)와 parent

lmkfox · 2025-09-09 · 조회 0
PHP 상속 오버라이드(override)와 parent
개념 정리 - 오버라이드(override): 자식 클래스가 부모로부터 상속받은 메서드와 같은 시그니처(이름·정적성·가시성 호환·타입 호환)를 가진 메서드를 재정의하는 것. 재정의하지 않은 멤버는 부모 동작을 그대로 사용한다.  - parent 키워드: 자식 클래스의 코드 안에서 부모 클래스의 멤버(메서드·정적 프로퍼티·상수)를 가리킬 때 사용한다. parent::메서드(), parent::__construct(), parent::$staticProp, parent::CONST, parent::class 등이 가능하다.  메서드 오버라이드 규칙 - 가시성(visibility) - 부모보다 좁게 만들 수 없다(public → protected/ private 불가). 넓히는 건 가능( protected → public 등). - 정적/비정적 일치 - 부모가 static이면 자식도 static이어야 하고, 인스턴스 메서드면 그대로 인스턴스 메서드여야 한다. 서로 바꾸면 에러. 근거: 정적 참조 규칙.  - 타입 호환(variance) - 반공변(Contravariance): 매개변수 타입은 자식에서 더 넓게 받을 수 있다. - 공변(Covariance): 반환 타입은 자식에서 더 구체적으로 좁힐 수 있다. - 이 규칙은 PHP 7.4부터 정식 지원.  - final 메서드/클래스는 오버라이드 불가. - private 메서드는 상속되지 않으므로 “오버라이드”가 아니라 새 메서드 정의가 된다. - 시그니처 검사 도구 - PHP 8.3의 #[\Override] 속성을 오버라이드하는 메서드에 붙이면, 실제로 부모/인터페이스의 동일 메서드를 정확히 재정의하지 않으면 컴파일 에러가 나서 실수를 잡아준다. __construct()에는 사용할 수 없다.  기본 예시 class Animal { public function speak(): string { return "sound"; } } class Dog extends Animal { #[\Override] // PHP 8.3+ public function speak(): string { // 반환 타입 공변(동일/더 구체적 가능) return "woof"; } } 가시성 넓히기 class Base { protected function run(): void {} } class Child extends Base { #[\Override] public function run(): void {} // OK: protected → public (넓힘) } 반공변 매개변수, 공변 반환타입 class User {} class Admin extends User {} class Repo { public function save(User $u): object { /*...*/ return new stdClass; } } class AdminRepo extends Repo { #[\Override] public function save(object $u): Admin { // 매개변수 넓힘(object), 반환 좁힘(Admin) // ... return new Admin(); } } parent 의 사용 부모 구현 호출(확장) class Logger { public function log(string $msg): void { echo "[base] $msg\n"; } } class FileLogger extends Logger { #[\Override] public function log(string $msg): void { parent::log($msg); // 부모 동작 재사용 file_put_contents('app.log', $msg.PHP_EOL, FILE_APPEND); } } 생성자 연쇄 호출 - 자식이 __construct()를 정의하면 부모 생성자는 자동으로 호출되지 않는다. 필요하면 parent::__construct()를 명시적으로 호출해야 한다.  class Conn { public function __construct(protected string $dsn) {} } class UserRepo extends Conn { public function __construct(string $dsn, private string $table = 'users') { parent::__construct($dsn); // 직접 호출 } } 정적 맥락/상수/클래스명 class A { public const TAG = 'A'; public static function who(){ return __CLASS__; } } class B extends A { public function demo(): void { echo parent::TAG, PHP_EOL; // 상수 echo parent::who(), PHP_EOL;// 정적 메서드 echo parent::class, PHP_EOL;// 부모 FQCN 문자열 } } parent는 현재 클래스의 직접 부모만 가리킨다. “조부모”를 바로 가리키는 parent::parent:: 같은 문법은 없고, 필요하면 조부모 클래스명을 직접 명시해 호출한다.  프로퍼티(속성)에 관하여 - PHP에서는 부모와 같은 이름의 프로퍼티를 자식에서 다시 선언할 수 있다. 다만 이는 “덮어쓰기”가 아니라 별도의 저장소가 생기는 것이며, 특히 부모의 private 프로퍼티는 애초에 상속되지 않기 때문에 같은 이름으로 선언해도 서로 독립적이다. 혼동을 피하려면 같은 이름으로 재선언하지 않는 것이 실무 권장. self::  /  static::  /  parent::  차이(정적 맥락) - self::는 정의된 클래스를, - static::는 호출 시점의 실제 클래스(Late Static Bindings) 를, - parent::는 직접 부모 클래스를 가리킨다. 공장 메서드, 싱글톤, ActiveRecord류에서는 보통 static::가 유용하다.  class Base { public static function make(): static { return new static(); } // LSB } class Child extends Base {} var_dump(get_class(Base::make())); // "Base" var_dump(get_class(Child::make())); // "Child" 트레이트와의 상호작용(요점) - 클래스가 트레이트를 사용할 때 메서드 결정 우선순위는 “클래스 > 트레이트 > 부모 클래스”다. 트레이트 내부에서 parent::method()를 호출하면, 트레이트를 포함한 클래스의 부모 체인에서 해당 메서드를 찾는다. (트레이트 자체에는 부모가 없다는 점만 유의.) 실수/버그 방지 체크리스트 - 시그니처가 부모와 호환되는지(가시성·정적성·타입) 확인. - 자식 생성자에서 부모 초기화가 필요하면 parent::__construct()를 꼭 호출.  - 정적 맥락 분기 필요 시 static::(LSB)와 parent::의 차이를 의도대로 사용.  - 오버라이드 의도를 명확히 하려면 PHP 8.3의 #[\Override] 사용.  - 같은 이름의 프로퍼티 재선언은 피한다(혼동과 디버깅 비용↑).

댓글

아직 댓글이 없습니다.

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