Extbase 엔터티 및 지연 로드 유형 속성

안녕 여러분,

오늘은 extbase에서 지연 로드된 엔터티 속성에 대한 속성 유형에 대해 쓰고 싶습니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     * @var Bar
     */
    private $bar;
}


PHP 7.3까지는 그랬지만 PHP 7.4+(속성 유형) 및 PHP 8.0+(공용체 유형)에서는 어떻게 처리해야 할까요?

글쎄, 7.4부터 시작하고 \TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage도 고려하십시오.

PHP 7.4에서 할 수 없는 것은 유니온 유형을 사용하는 것입니다. 다음 예제는 깔끔해 보이지만 구현이 불가능합니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     */
    private Bar|LazyLoadingProxy|null $bar = null;
}


그러나 PHP 7.4에서 누락된 공용체 유형은 여기서 우리가 직면한 유일한 제한 사항이 아닙니다. extbase의 리플렉션 프레임워크에는 extbase가 phpdoc 블록에서도 단일 유형만 감지할 수 있는 제한/버그가 있습니다. 따라서 주석@var Bar|LazyLoadingProxy은 extbase가 전체 속성 처리를 건너뛰기 때문에 이미 오류로 이어집니다.

따라서 마지막 예제는 누락된 언어 기능(PHP 7.4)으로 인해 작동하지 않지만 다음 예제는 extbase의 제한/버그로 인해 작동하지 않습니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     * @var Bar|LazyLoadingProxy
     */
    private $bar;
}


주어진 상황에서 가능한 한 엄격하고 의미 있게 접근하는 가장 좋은 방법은 무엇입니까? 내 현재 모범 사례는 다음과 같습니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     * @var Bar|null
     * @phpstan-var Bar|LazyLoadingProxy|null
     */
    private ?object $bar = null;
}


phpdoc이 extbase에서 우선하므로 ?object 속성 유형은 extbase와 관련이 없지만 이미 허용되는 유형을 좁혀 있습니다. IDE 및 phpstan과 같은 정적 코드 분석 도구에 대한 사용자 정의 주석 지원에 따라 속성이 LazyLoadingProxy 일 수 있음을 알거나 알 수 없지만 최소한 유형이 null 또는 Bar임을 알 수 있습니다. . 이 경우 PHPStan은 완전한 IDE 지원보다 더 중요한 모든 진실을 알게 될 것입니다.

ifLazyLoadingProxy라고 하면 ...\TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy::_loadRealInstance()는 프록시의 실제 값을 확인하기 위한 공개 API이지만 안타깝게도 해당 메서드의 반환 유형 주석이 잘못되었습니다. 구체적이지도 정확하지도 않은 object라고 되어 있습니다. 실제 반환 유형은 적어도 이론상으로는 실제로 동적이기 때문에 말하기 어렵습니다. 내부 논리가 실패할 가능성은 거의 없지만 정적 코드 분석 관점에서는 가능합니다. 프록시의 실제 값을 확인할 수 없는 경우 _loadRealInstance()는 속성의 실제 값을 반환하며 대부분의 경우 null입니다. 즉, 다음 코드는 중단될 수 있습니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     * @var Bar|null
     * @phpstan-var Bar|LazyLoadingProxy|null
     */
    private ?object $bar = null;

    public function getBar(): ?Bar
    {
        return $this->bar instanceof LazyLoadingProxy
            ? $this->bar->_loadRealInstance()
            : $this->bar;
    }
}


실제로는 이론적인 경우일 뿐이지만 이러한 게터에 대한 최선의 방법은 다음과 같습니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     * @var Bar|null
     * @phpstan-var Bar|LazyLoadingProxy|null
     */
    private ?object $bar = null;

    public function getBar(): ?Bar
    {
        if ($this->bar instanceof LazyLoadingProxy) {
            /** @var Bar|null $resolvedValue */
            $resolvedValue = $this->bar->_loadRealInstance();
            return $this->bar = $resolvedValue instanceof Bar
                ? $resolvedValue
                : null;
        }

        return $this->bar;
    }
}


LazyObjectStorage는 어떻습니까?



네, LazyObjectStorage도 있습니다. 어떻게 대처해야 할까요? LazyObjectStorageObjectStorage의 하위 클래스이므로 다음 코드를 작성할 수 있습니다.

use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;

class Foo
{
    /**
     * @Extbase\ORM\Lazy
     */
    private ObjectStorage $bar;

    public function __construct() {
        $this->initializeObject();
    }

    public function initializeObject() {
        $this->bar = new ObjectStorage();
    }

    public function getBar(): ObjectStorage
    {
        return $this->bar;
    }
}


여기서는 LazyObjectStorage 유형이 실제로 필요하지 않기 때문에 완전히 생략합니다. LazyObjectStorage의 API가 ObjectStorage의 API와 동일하고 기본 코드가 둘 다 동일하게 작동할 수 있기 때문에 PHPStan 등이 알아야 할 이점이 없습니다. IDE나 개인적으로 알 수 있습니다. 쉽죠?

오늘은 여기까지입니다.
좋은 시간 보내세요!

좋은 웹페이지 즐겨찾기