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
Type hinting for properties in PHP 7?
提问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
, __isset
and __unset
magic 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+ __set
magic method inside a trait in order to simulate this behaviour.
Here it is:
根据我仍然从该线程收到的通知,我相信很多人都遇到/正在遇到与我相同的问题。我对这种情况的解决方案是在 trait 中结合setter+ __set
magic 方法来模拟这种行为。这里是:
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 bar
as a private property so PHP will cast __set
automagically.
首先,定义bar
为私有属性,以便 PHP 会__set
自动转换。
__set
will 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 Bar
instance 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 ...