编写带或不带问号的nullable类型的教程

60 阅读1分钟

我一直对代码中的任何冗余或重复感到困扰。许多年前我就写过这个问题。看着这段代码,我就觉得很痛苦。

interface ContainerAwareInterface
{
    /**
     * Sets the container.
     */
    public function setContainer(ContainerInterface $container = null);
}

我们暂且不说对方法的评论内容的冗余。 也暂且不说不理解依赖注入的表现,如果库需要有这样一个接口。我准备另外写一篇文章,说在接口名称中使用Interface 这个词是对面向对象编程缺乏理解的表现。毕竟,我自己也经历过这种情况。

但究竟为什么要提到public 的能见度?这是个语气词。如果它不是公开的,那么它就不是一个接口,对吗?哦,还有人想到要把它变成一个 "标准"🤦♂️

呃,对不起,我的介绍太长了,我一直想知道的是,在写可选的nullable类型时,是用问号还是不用问号。即。

// bez
function setContainer(ContainerInterface $container = null);
// s
function setContainer(?ContainerInterface $container = null);

就个人而言,我一直倾向于第一种选择,因为问号给出的信息是多余的(是的,从语言的角度看,两种符号的意思是一样的)。同时,在PHP7.1之前,所有的代码都是这样写的,也就是增加了问号的版本,必须有一个很好的理由才能一下子改变它。

随着 PHP 8.0 的出现,我改变了主意,我将解释为什么。在属性的情况下,问号不是可选的。在这一问题上,PHP的尖叫声。

class Foo
{
	private Bar $foo = null;
}
// Fatal error: Default value for property of type Bar may not be null.
// Use the nullable type ?Bar to allow null default value

而且,从 PHP 8.0 开始,可以使用推广的属性,这样就可以写出这样的代码。

class Foo
{
	public function __construct(
		private ?Bar $foo = null,
		string $name = null,
	) {
		// ...
	}
}

在这里你可以看到不一致的地方。如果在代码中使用了?Bar(这是必要的),那么它后面应该是?string 一行。而如果我在某些情况下写了一个问号,我应该在所有情况下写一个问号。

问题是,使用联合类型string|null ,而不是问号,是否更好。例如,如果我想输入Stringable|string|null ,问号版本可能根本就不存在。