PHP 7의 속성에 대한 유형 힌트?


80

PHP 7은 클래스 속성에 대한 유형 힌트를 지원합니까?

내 말은, setter / getters 뿐만 아니라 속성 자체를 위해서도 말입니다 .

다음과 같은 것 :

class Foo {
    /**
     *
     * @var Bar
     */
    public $bar : Bar;
}

$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error

1
내가 아는 것은 아닙니다. 그러나, 일반적으로 어떤 속성 값에 대한 제약하는 것은 어쨌든 세터를 통해 수행해야합니다. setter는 "value"인수에 대한 유형 힌트를 쉽게 가질 수 있으므로 사용하는 것이 좋습니다.
— Niet the Dark Absol 2016 년

많은 프레임 워크는 보호 된 속성 을 사용 합니다 (주로 컨트롤러 용). 특히 그러한 경우에는 매우 유용 할 것입니다.
— CarlosCarucce

답변:


134

PHP 7.4 는 다음과 같은 유형의 속성을 지원합니다 .

class Person
{
    public string $name;
    public DateTimeImmutable $dateOfBirth;
}

PHP 7.3 및 이전 버전은이를 지원하지 않지만 몇 가지 대안이 있습니다.

유형 선언이있는 getter 및 setter를 통해서만 액세스 할 수있는 개인 속성을 만들 수 있습니다.

class Person
{
    private $name;
    public function getName(): string {
        return $this->name;
    }
    public function setName(string $newName) {
        $this->name = $newName;
    }
}

또한 공용 속성을 만들고 docblock을 사용하여 코드를 읽고 IDE를 사용하는 사람들에게 유형 정보를 제공 할 수 있지만 런타임 유형 검사는 제공하지 않습니다.

class Person
{
    /**
      * @var string
      */
    public $name;
}

그리고 실제로 getter와 setter와 docblock을 결합 할 수 있습니다.

좀 더 모험적인 경우와 가짜 속성을 만들 수있는 __get, __set, __isset및 __unset마술 방법 및 종류를 직접 확인하십시오. 그래도 추천 할 수 있을지 모르겠습니다.


정말 좋네요. 다음 릴리스에서 무엇이 나올지 기다릴 수 없습니다!
— CarlosCarucce

또 다른 중요한 문제는 참조 처리로, 유형 선언과 실제로 잘 상호 작용하지 않으며 이러한 속성에 대해 비활성화해야 할 수 있습니다. 성능 문제가 없어도 할 수 array_push($this->foo, $bar)없거나 말할 수 없거나 sort($this->foobar)큰 문제입니다.
— Andrea

유형의 강제는 어떻게 작동합니까? 예 : (new Person())->dateOfBirth = '2001-01-01';... 제공 declare(strict_types=0);됩니다. DateTimeImmutable생성자를 던지거나 사용 합니까? 이 경우 문자열이 잘못된 날짜이면 어떤 종류의 오류가 발생합니까? TypeError?
— lmerino

@Imerino DateTime (Immutable)에 대한 암시 적 변환이 없으며 그 적이 없습니다
— Andrea

12

7.4 이상 :

@Andrea가 지적했듯이 새 릴리스에서 구현 될 것이라는 좋은 소식입니다. 누군가 7.4 이전에 사용하려는 경우이 솔루션을 여기에 남겨 두겠습니다.


7.3 이하

이 스레드에서 여전히 수신하는 알림을 기반으로 많은 사람들이 내가 가진 동일한 문제를 가지고 있다고 생각합니다. 이 경우에 대한 내 솔루션은 이 동작을 시뮬레이션하기 위해 특성 내부에 setter + __setmagic 메서드를 결합하는 것이 었습니다 . 여기있어:

trait SettersTrait
{
    /**
     * @param $name
     * @param $value
     */
    public function __set($name, $value)
    {
        $setter = 'set'.$name;
        if (method_exists($this, $setter)) {
            $this->$setter($value);
        } else {
            $this->$name = $value;
        }
    }
}

그리고 여기에 데모가 있습니다.

class Bar {}
class NotBar {}

class Foo
{
    use SettersTrait; //It could be implemented within this class but I used it as a trait for more flexibility

    /**
     *
     * @var Bar
     */
    private $bar;

    /**
     * @param Bar $bar
     */
    protected function setBar(Bar $bar)
    {
        //(optional) Protected so it wont be called directly by external 'entities'
        $this->bar = $bar;
    }
}

$foo = new Foo();
$foo->bar = new NotBar(); //Error
//$foo->bar = new Bar(); //Success

설명

우선, barPHP가 __set 자동으로 캐스트되도록 private 속성으로 정의 합니다.

__set현재 객체 ( method_exists($this, $setter))에 선언 된 setter가 있는지 확인합니다 . 그렇지 않으면 평소처럼 값만 설정됩니다.

유형 힌트 인수 ( setBar(Bar $bar)) 를받는 setter 메서드 (setBar)를 선언합니다 .

PHP가 Bar인스턴스 가 아닌 것이 setter에 전달되고 있음을 감지하는 한, Fatal Error : Uncaught TypeError : Argument 1 pass to Foo :: setBar () must be an instance of Bar, instance of NotBar given to


4

PHP 7.4 수정 :

PHP 7.4부터 속성 ( 문서 / 위키 )을 입력 할 수 있습니다.

    class Foo
{
    protected ?Bar $bar;
    public int $id;
    ...
}

위키에 따르면 허용되는 모든 값은 다음과 같습니다.

  • bool, int, float, 문자열, 배열, 객체
  • 반복 가능
  • 자기, 부모
  • 모든 클래스 또는 인터페이스 이름
  • ? type // 여기서 "type"은 위 중 하나 일 수 있습니다.

PHP 7.4 미만

실제로는 불가능하며 실제로 시뮬레이션하는 방법은 4 가지뿐입니다.

  • 기본값
  • 주석 블록의 데코레이터
  • 생성자의 기본값
  • 게터와 세터

여기에 다 합쳐서

class Foo
{
    /**
     * @var Bar
     */
    protected $bar = null;

    /** 
    * Foo constructor
    * @param Bar $bar
    **/
    public function __construct(Bar $bar = null){
        $this->bar = $bar;
    }
    
    /**
    * @return Bar
    */
    public function getBar() : ?Bar{
        return $this->bar;
    }

    /**
    * @param Bar $bar
    */
    public function setBar(Bar $bar) {
        $this->bar = $bar;
    }
}

php 7.1 (nullable) 이후로 반환 값을? Bar로 입력 할 수 있습니다. 이는 null 일 수 있기 때문입니다 (php7.0에서는 사용할 수 없음).

php7.1 이후로 return을 void로 입력 할 수도 있습니다.


1

세터를 사용할 수 있습니다.

class Bar {
    public $val;
}

class Foo {
    /**
     *
     * @var Bar
     */
    private $bar;

    /**
     * @return Bar
     */
    public function getBar()
    {
        return $this->bar;
    }

    /**
     * @param Bar $bar
     */
    public function setBar(Bar $bar)
    {
        $this->bar = $bar;
    }

}

$fooInstance = new Foo();
// $fooInstance->bar = new NotBar(); //Error
$fooInstance->setBar($fooInstance);

산출:

TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.