PHP 7 中的属性类型提示?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37254695/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:07:52  来源:igfitidea点击:

Type hinting for properties in PHP 7?

phpattributesphp-7type-hintingvariable-types

提问by CarlosCarucce

Does php 7 support type hinting for class properties?

php 7 是否支持类属性的类型提示?

I mean, not just for setters/gettersbut for the property itself.

我的意思是,不仅针对setter/getter,而且针对属性本身。

Something like:

就像是:

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

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

回答by Andrea

PHP 7.4 will support typed propertieslike so:

PHP 7.4将支持如下类型的属性

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


PHP 7.3 and earlier do not support this, but there are some alternatives.

PHP 7.3 及更早版本不支持此功能,但有一些替代方案。

You can make a private property which is accessible only through getters and setters which have type declarations:

您可以创建一个只能通过具有类型声明的 getter 和 setter 访问的私有属性:

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

You can also make a public property and use a docblock to provide type information to people reading the code and using an IDE, but this provides no runtime type-checking:

您还可以创建一个公共属性并使用 docblock 为阅读代码和使用 IDE 的人提供类型信息,但这不提供运行时类型检查:

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

And indeed, you can combine getters and setters and a docblock.

事实上,你可以结合 getter 和 setter 以及一个 docblock。

If you're more adventurous, you could make a fake property with the __get, __set, __issetand __unsetmagic methods, and check the types yourself. I'm not sure if I'd recommend it, though.

如果你更喜欢冒险,你可以使用假的性质__get__set__isset__unset魔术方法,并检查自己的类型。不过,我不确定我是否会推荐它。

回答by CarlosCarucce

7.4+:

7.4+:

Good news that it will be implemented in the new releases, as @Andrea pointed out. I will just leave this solution here in case someone wants to use it prior to 7.4

正如@Andrea 指出的那样,好消息是它将在新版本中实施。如果有人想在 7.4 之前使用它,我将把这个解决方案留在这里



7.3 or less

7.3 或更少

Based on the notifications I still receive from this thread, I believe that many people out there had/is having the same issue that I had. My solution for this case was combining setters+ __setmagic method inside a trait in order to simulate this behaviour. Here it is:

根据我仍然从该线程收到的通知,我相信很多人都遇到/正在遇到与我相同的问题。我对这种情况的解决方案是在 trait 中结合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;
        }
    }
}

And here is the demonstration:

这是演示:

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


Explanation

解释

First of all, define baras a private property so PHP will cast __setautomagically.

首先,定义bar为私有属性,以便 PHP 会__set自动转换

__setwill check if there is some setter declared in the current object (method_exists($this, $setter)). Otherwise it will only set its value as it normally would.

__set将检查当前对象 ( method_exists($this, $setter)) 中是否声明了一些 setter 。否则它只会像往常一样设置它的值。

Declare a setter method (setBar) that receives a type-hinted argument (setBar(Bar $bar)).

声明一个接收类型提示参数 ( setBar(Bar $bar))的 setter 方法 (setBar )。

As long as PHP detects that something that is not Barinstance is being passed to the setter, it will automaticaly trigger a Fatal Error: Uncaught TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of NotBar given

只要 PHP 检测到一些不是Bar实例的东西被传递给 setter,它就会自动触发一个致命错误:未捕获的类型错误:传递给 Foo::setBar() 的参数 1 必须是 Bar 的实例,NotBar 的实例给定

回答by Bruno Guignard

It is actually not possible and you only have 4 ways to actually simulate it :

这实际上是不可能的,你只有 4 种方法来实际模拟它:

  • Default values
  • Decorators in comment blocks
  • Default values in constructor
  • Getters and setters
  • 默认值
  • 注释块中的装饰器
  • 构造函数中的默认值
  • 吸气剂和吸气剂

I combined all of them here

我把它们都结合在这里

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

Note that you actually can type the return as ?Bar since php 7.1 (nullable) because it could be null (not available in php7.0.)

请注意,从 php 7.1 开始,您实际上可以将返回值输入为 ?Bar(可为空),因为它可能为 null(在 php7.0 中不可用。)

You also can type the return as void since php7.1

从 php7.1 开始,您也可以将返回值输入为 void

回答by Richard

You can use setter

你可以使用二传手

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

Output:

输出:

TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...