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.