개발블로그

[객체지향] PHP readonly 속성과 클래스 본문

STUDY/PHP

[객체지향] PHP readonly 속성과 클래스

devmel 2026. 9. 6. 15:22
Contents 접기
 

개념

의미

속성을 초기화한 뒤 값을 다시 대입하거나 수정하지 못하도록 제한하는 키워드

 

객체를 만들 때 설정한 식별자나 생성 시각처럼, 이후 유지해야 하는 값에 사용할 수 있음. 

읽기 전용 속성은 PHP8.1부터 지원함

 

비교  : final vs readonly

구분 final readonly
클래스에 적용 클래스 상속 금지 모든 인스턴스 속성에 읽기 전용 규칙 적용
속성에 적용 자식 클래스에서 속성 재선언 금지 초기화 이후 속성 변경 제한
메서드에 적용 오버라이딩 금지 적용 불가

 

- 동시 적용 가능 

 

 


 

문법

 

class ClassName
{
	// 속성 선언, 아직 값은 없음
    public readonly string $propertyName;

	// 첫 값 대입으로 초기화
    public function __construct(string $value)
    {
        $this->propertyName = $value;
    }
}

 

ex)

class UserProfile
{
    public readonly int $id;

    public function __construct(int $id)
    {
        $this->id = $id;
    }
}

$user = new UserProfile(1001);

echo $user->id; // 1001

$user->id = 2002; // 오류: 초기화된 readonly 속성 변경

 

선언과 초기화

선언만으로 값이 생기는 것이 아니라, 허용된 범위에서 처음 값을 대입해야 사용할 수 있음.

class UserProfile
{
    public readonly int $id;
}

$user = new UserProfile();

echo $user->id; // 오류: 초기화 전 접근

 

[ 허용된 범위 ]

위치 PHP 8.1~8.3 PHP 8.4 이상
선언한 클래스 내부 가능 가능
자식 클래스 내부 불가능 가능
클래스 외부 불가능 불가능

 

기본값 선언 제한

일반적인 속성 선언 위치에서는 기본값을 지정할 수 없음

- 대신 생성자 매개변수에 기본값을 두고, 그 값을 속성에 대입할 수 있다.

ex)

class UserProfile
{
    public readonly int $id = 1001; // 오류
}

// 아래는 가능
class UserProfile
{
    public readonly int $id;

    public function __construct(int $id = 1001)
    {
        $this->id = $id;
    }
}

$user = new UserProfile();
echo $user->id; // 1001

 

 

적용타입

readonly 속성에는 타입을 반드시 선언해야 함.

(여러 종류의 값 허용시, mixed사용 가능)

 

 

변경 제한

단순한 재대입뿐 아니라, 증가 연산이나 배열 요소 수정처럼 속성값을 변경하는 동작도 제한

 

ex)

class UserProfile
{
    public readonly int $id;
    public readonly array $roles;

    public function __construct(int $id, array $roles)
    {
        $this->id = $id;
        $this->roles = $roles;
    }
}

$user = new UserProfile(1001, ["user"]);

echo $user->id;       // 1001
echo $user->roles[0]; // user

$user->id = 2002;          // 재대입 불가
$user->id = 1001;          // 같은 값을 다시 대입해도 불가
$user->id++;              // 증가 연산 불가

$user->roles[] = "admin";  // 배열 요소 추가 불가
$user->roles[0] = "guest"; // 배열 요소 변경 불가
unset($user->roles[0]);    // 배열 요소 삭제 불가

 

값의 조회와 활용

저장된 값을 읽어 다른 계산이나 처리에 사용하는 것은 가능 

ex)

$nextId = $user->id + 1;

$roles = $user->roles;
$roles[] = "admin";

echo $nextId;          // 1002
echo count($roles);    // 2
echo count($user->roles); // 1

 

객체 속성과 내부 상태 변경

readonly 속성에 객체를 저장하면, 그 속성이 가리키는 객체를 교체할 수 없음

단, 저장된 객체 내부의 속성까지 자동으로 읽기 전용이 되는 것은 아님.

 

ex)

class Address
{
    public string $city;

    public function __construct(string $city)
    {
        $this->city = $city;
    }
}

class UserProfile
{
    public readonly Address $address;

    public function __construct(Address $address)
    {
        $this->address = $address;
    }
}

$user = new UserProfile(new Address("Seoul"));

// 내부 값은 변경 가능
$user->address->city = "Busan";
echo $user->address->city; // Busan

// 객체 교체는 불가
$user->address = new Address("Jeju");
// 오류: 초기화된 readonly 속성에 다른 객체 대입

 

 

 

 


 

읽기 전용 클래스

 

개념

클래스에 readonly를 붙이면, 해당 클래스의 모든 인스턴스 속성에 읽기 전용 규칙이 적용됨

속성마다 readonly를 반복해서 작성할 필요가 없음 

(8.2 부터 가능)

 

문법

readonly class ClassName // 읽기 전용 클래스 선언
{
    public string $propertyName; // 자동으로 readonly 규칙이 적용되는 속성
    
    // static propery는 만들 수 없음

    public function __construct(string $value)
    {
        $this->propertyName = $value;
    }
}

 

ex)

readonly class UserProfile
{
    public int $id;
    public string $name;

    public function __construct(int $id, string $name)
    {
        $this->id = $id;
        $this->name = $name;
    }
}

$user = new UserProfile(1001, "Kim");

echo $user->id;   // 1001
echo $user->name; // Kim

$user->name = "Lee"; // 오류: 초기화된 readonly 속성 변경

// 선언되지 않은 $email을 추가하면 오류 발생
$user->email = "kim@example.com"; // 오류: 동적 속성 추가

 

상속 규칙

readonly 클래스를 상속하는 자식 클래스도 readonly로 선언해야 함

ex)

readonly class BaseProfile
{
}

readonly class UserProfile extends BaseProfile
{
}

 

 

 


 

주의점

 

초기화 누락

값을 읽기 전에 초기화되어야 한다. 

- null을 허용하는 타입이라고 해서 자동으로 null이 저장되지는 않음

 

내부 상태의 변경 가능성

readonly 속성에 객체를 저장하면 그 객체를 교체하는 것은 제한되지만, 내부 상태는 변경될 수 있음.

객체 전체의 불변성이 필요하다면 내부 객체가 제공하는 속성과 메서드까지 확인해야 함

 

객체 복제 시 재초기화

php 8.3부터는 __clone()에서 복제본의 readonly 속성을 한 번 재초기화할 수 있음

=> 복제 과정에서 적용되는 예외이며, 일반 메서드에서 이미 초기화된 속성을 다시 대입할 수 있다는 뜻은 아님 

 

ex)

class UserProfile
{
    public readonly Address $address;

    public function __construct(Address $address)
    {
        $this->address = $address;
    }

    public function __clone(): void
    {
        $this->address = clone $this->address;
    }
}

// 앞서 정의만 Address 클래스를 사용하는데, 복제 시 주소 객체도 복제하여 원본과 복제본이 
// 같은 주소 객체를 공유하지 않도록 함

 

 

 

'STUDY > PHP' 카테고리의 다른 글

[객체지향] PHP final 키워드  (0) 2026.09.05
[객체지향] PHP Trait  (1) 2026.09.05
PHP 변수 대입과 객체 복제  (1) 2026.09.05
[객체지향] PHP 매직 메서드  (0) 2026.09.05
[객체지향] PHP static과 스코프 해석 연산자  (0) 2026.09.05