>백엔드 개발 >PHP8 >PHP8.1의 새로운 기능에 대한 자세한 설명: 읽기 전용 속성 읽기 전용 속성

PHP8.1의 새로운 기능에 대한 자세한 설명: 읽기 전용 속성 읽기 전용 속성

藏色散人
藏色散人원래의
2021-11-10 15:14:473617검색

이 기사는 번역되었습니다. 원본 주소: https://stitcher.io/blog/php-81-readonly-properties

PHP 8.1: 읽기 전용 속성

수년 동안 저는 PHP를 사용해 왔습니다. 데이터 전송 개체 및 값 작성 개체가 매우 쉬워집니다. PHP 5.6의 DTO(

class BlogData
{
    /** @var string */
    private $title;
    
    /** @var Status */
    private $status;
    
    /** @var \DateTimeImmutable|null */
    private $publishedAt;
   
   /**
    * @param string $title 
    * @param Status $status 
    * @param \DateTimeImmutable|null $publishedAt 
    */
    public function __construct(
        $title,
        $status,
        $publishedAt = null
    ) {
        $this->title = $title;
        $this->status = $status;
        $this->publishedAt = $publishedAt;
    }
    
    /**
     * @return string 
     */
    public function getTitle()
    {
        return $this->title;    
    }
    
    /**
     * @return Status 
     */
    public function getStatus() 
    {
        return $this->status;    
    }
    
    /**
     * @return \DateTimeImmutable|null 
     */
    public function getPublishedAt() 
    {
        return $this->publishedAt;    
    }
}

)를 예를 들어 PHP 8.0의 DTO인

class BlogData
{
    public function __construct(
        private string $title,
        private Status $status,
        private ?DateTimeImmutable $publishedAt = null,
    ) {}
    
    public function getTitle(): string
    {
        return $this->title;    
    }
    
    public function getStatus(): Status 
    {
        return $this->status;    
    }
    
    public function getPublishedAt(): ?DateTimeImmutable
    {
        return $this->publishedAt;    
    }
}

와 비교해 보세요. 꽤 다르지만 여전히 큰 문제가 있다고 생각합니다. 모든 게터입니다. 개인적으로 저는 PHP 8.0과 향상된 속성 이후로 더 이상 사용하지 않습니다. 저는 getter를 추가하는 것보다 공용 속성을 사용하는 것을 선호합니다.

class BlogData
{
    public function __construct(
        public string $title,
        public Status $status,
        public ?DateTimeImmutable $publishedAt = null,
    ) {}
}

객체 지향 순수주의자는 이 접근 방식을 좋아하지 않습니다. 객체의 내부 상태는 직접 노출되어서는 안 되며 외부에서 변경할 수도 없습니다.

Spatie의 프로젝트에는 공공 속성이 있는 DTO 및 VO를 외부에서 변경해서는 안 된다는 내부 스타일 가이드 규칙이 있습니다. 이는 잘 작동하는 것으로 보이며 오랫동안 이를 수행해 왔지만 문제가 발생하지 않았습니다.

그러나 그렇습니다. 언어에서 공공 자산이 전혀 재정의되지 않도록 보장한다면 더 좋을 것이라는 데 동의합니다. PHP 8.1은 읽기 전용 키워드를 도입하여 이러한 모든 문제를 해결했습니다:

class BlogData
{
    public function __construct(
        public readonly string $title,
        public readonly Status $status,
        public readonly ?DateTimeImmutable $publishedAt = null,
    ) {}
}

이 키워드는 기본적으로 이름에서 알 수 있는 것과 같은 역할을 합니다. 일단 속성이 설정되면 더 이상 재정의할 수 없습니다:

$blog = new BlogData(
    title: 'PHP 8.1: readonly properties', 
    status: Status::PUBLISHED, 
    publishedAt: now()
);
$blog->title = 'Another title';
Error: Cannot modify readonly property BlogData::$title

객체가 생성되면, 이는 다시 변경될 수 없으며 코드를 작성할 때 일정 수준의 확실성과 마음의 평화를 제공합니다. 예상치 못한 일련의 데이터 변경은 다시는 발생할 수 없습니다.

물론, 여전히 데이터를 새 개체에 복사하고 프로세스에서 일부 속성을 변경할 수 있기를 원합니다. 이 문서의 뒷부분에서 읽기 전용 속성을 사용하여 이를 수행하는 방법에 대해 설명하겠습니다. 먼저, 좀 더 자세히 살펴보겠습니다.

PHP 8.1에 대해 더 알고 싶으십니까? PHP 8.1에 대한 경로가 있습니다. 앞으로 10일 동안 PHP 8.1의 새로운 기능과 기존 기능에 대한 이메일을 매일 받게 됩니다. 그러면 자동으로 구독이 취소되므로 스팸이나 후속 이메일을 받지 않게 됩니다. 지금 구독하세요!

#입력 속성만

읽기 전용 속성은 입력된 속성과만 함께 사용할 수 있습니다:

class BlogData
{
    public readonly string $title;
    
    public readonly $mixed;
}

그러나 혼합을 유형 힌트로 사용할 수 있습니다:

class BlogData
{
    public readonly string $title;
    
    public readonly mixed $mixed;
}

이 제한의 이유는 속성 유형, null 생성자에 명시적인 값이 제공되지 않으면 PHP는 자동으로 속성 값을 설정합니다. 읽기 전용과 결합된 이 동작은 불필요한 혼란을 초래할 수 있습니다.

#일반 속성 및 승격 속성

두 가지의 예를 확인했습니다. 일반 속성과 승격 속성에 읽기 전용을 추가할 수 있습니다.

class BlogData
{
    public readonly string $title;
    
    public function __construct(
        public readonly Status $status, 
    ) {}
}

#기본값 없음

읽기 전용 속성은 기본값을 가질 수 없습니다.

class BlogData
{
    public readonly string $title = 'Readonly properties';
}

즉, 승격된 속성이 아닌 이상 :

class BlogData
{
    public function __construct(
        public readonly string $title = 'Readonly properties', 
    ) {}
}

승격된 속성의 기본값은 클래스 속성의 기본값으로 사용되지 않고 생성자의 매개변수에만 적용되므로 속성 승격이 허용됩니다. . 뒤에서 위 코드는 다음과 같이 변환됩니다.

class BlogData
{
    public readonly string $title;
    
    public function __construct(
        string $title = 'Readonly properties', 
    ) {
        $this->title = $title;
    }
}

실제 속성에 기본값이 할당되지 않은 방식을 확인할 수 있습니다. 그런데 읽기 전용 속성에 대한 기본값이 허용되지 않는 이유는 해당 형식의 상수와 전혀 다르지 않기 때문입니다.

#legacy

상속 중에 읽기 전용 플래그를 변경할 수 없습니다.

class Foo
{
    public readonly int $prop;
}
class Bar extends Foo
{
    public int $prop;
}

이 규칙은 양방향으로 적용됩니다. 상속 중에 읽기 전용 플래그를 추가하거나 제거할 수 없습니다.

#설정 해제는 허용되지 않습니다.

읽기 전용 속성이 설정되면 이를 변경하거나 설정 해제할 수도 없습니다.

$foo = new Foo('value');
unset($foo->prop);

#Reflection

플래그뿐만 아니라 새로운 방법이 있습니다. ReflectionProperty::isReadOnly()ReflectionProperty::IS_READONLY

#Clone

그래서 읽기 전용 속성을 변경할 수 없고 설정을 해제할 수 없는 경우 DTO 또는 VO의 복사본을 어떻게 만들고 일부 데이터를 변경하시겠습니까? 해당 값을 덮어쓸 수 없으므로 복제할 수 없습니다. 실제로 미래에 이 동작을 허용하는 구성으로 복제하려는 아이디어가 있었지만 현재의 문제는 해결되지 않습니다.

글쎄, 약간의 반사 마법에 의존한다면 읽기 전용 속성이 변경된 객체를 복사할 수 있습니다. 생성자를 호출하지 않고 개체를 만든 다음(리플렉션을 사용하여 수행할 수 있음) 각 속성을 수동으로 복사하여(때로는 해당 값을 덮어씀) 실제로 개체를 "복제"하고 읽기 전용 속성을 변경할 수 있습니다.

이 작업을 위해 작은 패키지를 만들었고 다음과 같이 진행됩니다.

class BlogData
{
    use Cloneable;
    public function __construct(
        public readonly string $title,
    ) {}
}
$dataA = new BlogData('Title');
$dataB = $dataA->with(title: 'Another title');

실제로 저는 이 모든 것의 메커니즘을 설명하는 전용 블로그 게시물을 썼는데, 여기에서 읽을 수 있습니다.

이것은 읽기 전용 속성에 관한 것입니다. 많은 DTO 및 VO를 처리하고 코드 전체의 데이터 흐름을 신중하게 관리해야 하는 프로젝트에서 작업하는 경우 이는 훌륭한 기능이라고 생각합니다. 읽기 전용 속성을 가진 불변 객체는 이와 관련하여 많은 도움이 됩니다.

위 내용은 PHP8.1의 새로운 기능에 대한 자세한 설명: 읽기 전용 속성 읽기 전용 속성의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.