他们专门为“后端PHP开发人员”课程的学生准备了一篇有关流行工具副作用的有趣文章的翻译。
在PHP中使用日期和时间有时会很烦人,因为这会导致代码中出现意外错误:
$startedAt = new DateTime('2019-06-30 10:00:00'); $finishedAt = $startedAt->add(new DateInterval('PT3M')); var_dump($startedAt->format('Ymd H:i:s'));
$startdate
和
$finishdate
都急着三分钟,因为诸如
add ()
,
sub()
或
$finishdate
modify()
还会在返回之前对其进行修改的DateTime对象进行修改。 当然,以上示例显示了不良行为。
我们可以通过在与对象进行交互之前复制引用的对象来解决此错误,例如:
$startedAt = new DateTime('2019-06-30 10:00:00'); $finishedAt = clone $startedAt; $finishedAt->add(new DateInterval('PT3M'));
每当我遇到一个PHP代码克隆时,它闻起来就像是有人的失败代码体系被黑客入侵。 在这种情况下,我们使用克隆来避免改变行为,但是与此同时,代码变得丑陋并获得了很多不必要的噪音。
或者,可以通过将原始
DateTime
实例转换为
DateTime
来解决此问题:
$startedAt = new DateTime('2019-06-30 10:00:00'); $finishedAt = DateTimeImmutable::createFromMutable($startedAt)->add(new DateInterval('PT3M'));
为什么不从一开始就使用
DateTimeImmutable
?
毫不妥协地使用DateTimeImmutable
使用
DateTimeImmutable
封装方法,而不是手动应用安全方法来防止在传递日期/时间对象时发生意外更改,该方法封装了方法,从而使您的代码更可靠。
$startedAt = new DateTimeImmutable('2019-06-30 10:00:00'); $finishedAt = $startedAt->add(new DateInterval('PT3M')); var_dump($startedAt->format('Ymd H:i:s'));
在大多数情况下,日期的概念被视为一个值,我们将日期与它们的值进行比较,并且当我们更改日期时,日期将变为不同的日期。 所有这些都与
价值对象的概念完美相关,
价值对象的重要特征之一是它们是不可变的。
详细的编码风格
不变性迫使您每次与
DateTimeImmutable
对象进行交互时都要明确地重新分配它,因为它从不更改其值,而是返回一个副本。 在使用DateTime多年之后,由于可变性是许多命令式编程语言中的默认设置,因此很难摆脱使用它的习惯,并且要遵循促进重新映射的新代码编写风格:
$this->expiresAt = $this->expiresAt->modify('+1 week');
如果我们忽略分配并错误地使用
DateTimeImmutable
,则统计分析工具(例如
PHPStan 及其扩展之一 )会警告我们。
但是,当我们对基元的值执行算术运算时,例如
$a + 3;
变化,这种对变异性的认知偏差就被抑制
$a + 3;
。 就其本身而言,这被认为是毫无意义的陈述,显然缺少重新分配:
$a = $a + 3;
或
$A += 3;
。 在值对象的情况下使用这样的东西会很酷,对吧?
一些编程语言具有称为
操作符重载的语法糖,它允许您在用户定义的类型和类中实现操作符,以便它们的行为就像原始数据类型一样。 我不介意PHP是否从其他编程语言中借用了这个技巧,我们可以这样编写:
$this->expiresAt += '1 week';
一次性计算
有人认为,就性能而言,最好使用
DateTime
,因为计算是在同一执行区域内执行的。 但是,这是可以接受的,如果您不需要执行数百个操作,并且您还记得垃圾收集器将收集到旧的
DateTimeImmutable
对象的链接,那么在大多数情况下,实际上,内存消耗不会成为问题。
日期/时间库
Carbon是一个非常流行的库,它扩展了PHP中的Date / Time API,并添加了丰富的功能集。 更准确地说,它扩展了
DateTime
可变类的API,其使用与本文的主题背道而驰。
因此,如果您喜欢使用Carbon,但更喜欢不变性,建议您熟悉
Chronos 。 这是一个独立的库,最初基于Carbon,特别注意提供不可变的默认日期/时间对象,但在需要时还包括可变选项。
编辑(07/05/2019):事实证明Carbon拥有不可变的日期/时间选项,这是一个很大的优点。 但是,我喜欢Chronos的原因是,与Carbon不同,它鼓励并促进代码和文档中的默认不变性,而这是本文中的决定性因素。
最后的想法
DateTimeImmutable
最早是在古老的PHP 5.5中引入的,但令我惊讶的是,许多开发人员刚刚才发现它。 尽可能在默认情况下默认使用
DateTimeImmutable
,但请记住我谈到的一些权衡因素,我认为这更多是习惯问题和思维方式的转变。
仅此而已。 按照传统,我们正在等待您的评论,朋友。