web-dev-qa-db-ja.com

PHP 7のプロパティのタイプヒンティング?

PHP 7はクラスプロパティの型ヒントをサポートしていますか?

つまり、setters/gettersだけでなく、プロパティ自体に対してもです。

何かのようなもの:

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

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

PHP 7.4 型付きプロパティをサポートします 次のように:

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

PHP 7.3以前はこれをサポートしていませんが、いくつかの選択肢があります。

型宣言を持つゲッターとセッターを介してのみアクセス可能なプライベートプロパティを作成できます。

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;
}

実際、ゲッターとセッター、およびdocblockを組み合わせることができます。

もっと冒険したい場合は、 __get__set__issetおよび__unsetマジックメソッド で偽のプロパティを作成し、チェックすることができます。タイプを自分で。しかし、私はそれをお勧めするかどうかわかりません。

106
Andrea

7.4 +:

@Andreaが指摘したように、新しいリリースで実装されるという良いニュースです。誰かが7.4より前にそれを使用したい場合に備えて、このソリューションをここに残します


7.3以下

私はまだこのスレッドから受け取った通知に基づいて、世の中の多くの人々が私と同じ問題を抱えていた/持っていると信じています。この場合の私のソリューションは、この動作をシミュレートするために、特性内でsetters + __setマジックメソッドを組み合わせることでした。ここにあります:

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

説明

まず、PHPが__setautomagicallyをキャストするように、barをプライベートプロパティとして定義します。

__setは、現在のオブジェクトで宣言されているセッターがあるかどうかを確認します(method_exists($this, $setter))。それ以外の場合、通常のように値を設定するだけです。

型ヒント引数(setBar(Bar $bar))を受け取るセッターメソッド(setBar)を宣言します。

PHPがBarインスタンスではないものがセッターに渡されていることを検出する限り、致命的なエラーを自動的にトリガーします:Uncaught TypeError:Argument 1 to Foo :: setBar()は、Barのインスタンス、NotBarのインスタンスである必要があります

5
CarlosCarucce

実際には不可能であり、実際にシミュレートする方法は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;
    }
}

Null(php7.0では使用不可)になる可能性があるため、実際には、戻り値を?Barとしてphp 7.1(null可能)から入力できることに注意してください。

Php7.1以降、戻り値をvoidとして入力することもできます

1
Bruno Guignard

セッターを使用できます

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 ...
0
Richard