15.2 오버라이딩

클래스 상속은 부모의 기능을 이어받으면서 새로운 클래스를 생성합니다. 즉, 부모의 모든 메서드와 프로퍼티를 자식 클래스에게 사용 가능하도록 상속합니다.

하지만, 상속받은 기능 하나를 변경고자 할 때는 어떻게 해야 할까요? 기능이 약간 변경이 되거나 새롭게 재정의를 할 수 있습니다. 클래스는 이런 경우를 위해서 기존의 기능을 다시 덮어써서 다시 선언할 수 있는 오버라이딩이라는 기능을 제공합니다.

오버라이딩이란 상속받은 클래스의 메서드 중에서 특정 하나의 메서드의 함수를 다시 정의해서 사용을 하는 경우 입니다. 오버라이딩은 상속 전에 미리 구현해 놓은 메서드가 있을 때 상속받은 자식 클래스에서 다시 새로운 코드로 작성이 필요할 경우 매우 유용합니다.



15.2.1 오버라이딩 예제

그럼 상속받은 클래스를 오버라이딩을 통해 재정의하는 것을 예제를 통해서 학습해 보도록 하겠습니다. 오버라이딩 작성은 매우 간단합니다.

예제 파일 override-01.php

<?php
    // 기본 클래스 a를 생성합니다.
    class a
    {
        public function isAdult($age)
        {
            if($age>=18) return true; else return false;
        }

    }

    // 기본 클래스 a를 상속하는 b 클래스를 생성합니다.
    class b extends a
    {
        // a의 메서드를 오버라이딩 다시 정의합니다.
        public function isAdult($age)
        {
            if($age>=20) return true; else return false;
        }

        public function whatIs($string,$age)
        {
            echo "myName is: " . $string . "<br>";

            if ($this->isAdult($age)){
                echo "성인입니다.<br>";
            } else {
                echo "미성년입니다.<br>";
            }

        }

        public function old18($string,$age)
        {
            echo "myName is: " . $string . "<br>";

            if (parent::isAdult($age)){
                echo "성인입니다.<br>";
            } else {
                echo "미성년입니다.<br>";
            }

        }

    }

    // 상속받은 b 클래스 인스턴스를 생성합니다.
    $obj = new b();

    echo "오버라이딩한 클래스의 결과<br>";
    // 새롭게 추가한 메서드 함수를 사용할 수 있습니다.
    $obj->whatIs("hojinLee",18);
    $obj->whatIs("jiny",17);

    // 오버라이딩 이전의 메서드를 이용합니다.
    // parent 키워드 이용
    echo "===== <br>";
    echo "오버라이딩 이전의 클래스의 결과<br>";
    $obj->old18("hojinLee",18);
    $obj->old18("jiny",17);
?>

결과

오버라이딩한 클래스의 결과
myName is: hojinLee
미성년입니다.
myName is: jiny
미성년입니다.
=====
오버라이딩 이전의 클래스의 결과
myName is: hojinLee
성인입니다.
myName is: jiny
미성년입니다.

위의 예는 클래스의 오버라이딩 예입니다. 클래스의 메서드를 오버라이드하는 별도의 문법적 키워드는 없습니다. 그냥 동일한 메서드명으로 다시 작성하면 자동으로 오버라이딩되어 처리됩니다.

클래스 a에는 isAdult() 메서드가 선언되어 있습니다. 클래스 b는 클래스 a를 상속받았지만 클래스 정의 내에서 클래스 a의 메서드와 동일한 이름의 isAdult() 메서드가 또 존재합니다.

기존 부모 클래스의 메서드와 자식 클래스내에 동일한 이름의 메서드가 있을 경우 자식의 메서드를 우선으로 처리합니다. 즉, 동일한 이름으로 겹치게 되면 자동으로 오버라이딩된 것으로 처리합니다.

만일 오버라이딩하기 전의 부모의 메서드를 사용하고 싶다면 parent:: 키워드를 사용하면 됩니다.



15.2.2 final 키워드

오버라이딩 기능은 부모의 메서드를 재정의 하여 사용할 수 있었습니다. 하지만 중요한 메서드의 경우 상속후에 재정의하여 사용할 경우 문제가 발생할 수도 있습니다. 이런 경우, 오버라이딩을 하지 못하게 할 필요성이 있습니다. 클래스에서는 상속을 받아도 오버라이딩이 되지 않도록 방지하는 final 키워드를 제공합니다.

final로 선언된 메서드는 상속되어도 오버라이딩을 할 수 없습니다.

예제 파일 final-01.php

<?php
    // php.ini의 수정 없이, 화면에 에러 발생 시 출력할 수 있습니다.
    error_reporting(E_ALL);
    ini_set("display_errors", 1);

    // 기본 클래스 a를 생성합니다.
    class a
    {

        final public function copyright (){
            // 본 메서드 함수는 대체되지 않습니다.
            echo "copyright all Right JinyPHP";
        }

    }

    // 기본 클래스 a를 상속하는 b 클래스를 생성합니다.
    class b extends a
    {

        public function copyright(){
            // 본 메서드 함수는 대체되지 않습니다.
            echo "copyright all Right ...";
        }

     
    }

    // 상속받은 b 클래스 인스턴스를 생성합니다.
    $obj = new b();

    $obj->copyright();

?>

오류 메시지

/jinyphp/final-01.php - Cannot override final method a::copyright() in C:\php-7.1.4-Win32-VC14-x86\jinyphp\final-01.php on line 27

위의 예제는 클래스의 오버라이딩 방지에 대한 예입니다. final키워드로설정된 메서드는 상속후 다시 오버라이딩을 할 수 없습니다. 만일 final로 선언된 메서드를 오버라이딩을 할 경우 “cannot override final method” 오류가 표시됩니다.

문법

final class users
{
}

참고로, 만일 class 키워드 앞에 final 키워드를 입력하면 클래스 전체가 final로 설정됩니다.