日期包摘要,第一部分
不幸的是,夏天结束了。让我们看看我是如何处理我们全新日期包的 GSoC 项目的。
这就结束了
对我来说,这是一个非常美好的夏天,遗憾的是它过得如此之快。我的主要目标是提供不可变的 DateTime 对象。任务完成!对我个人来说是个好消息,我希望对大家也好。让我们快速看一下 UML 类图(在 yuml.me 中创建)
那里有很多东西,所以我需要解释一些。
为什么 Joomla\DateTime\DateTime 不扩展 PHP DateTime?
PHP DateTime 是可变的,我的主要目标是使 DateTime 类不可变。你可以在这里了解更多关于它的信息这里。更准确地说,我的目标是创建 DateTime 作为不可变的值对象。
为什么我创建了一个新的 DateInterval?
原因和 DateTime 对象一样。不用担心,它只是一个包装器,几乎提供了 PHP 版本的所有功能。甚至更多 - 现在你可以将间隔相加。唯一不支持的功能是 - 你不能改变 DateInterval 的值。但这是我创建新的 DateInterval 的目的,所以可以忽略。
如果你需要 PHP DateTime 或 DateInterval 怎么办?
有时你需要 PHP 版本的 DateTime 或 DateInterval。你可以通过调用 getDateTime() 或 getDateInterval() 来轻松获取这些对象。
日期和 DateTime 之间没有继承关系
在这里我尝试了多种方法。我尝试了两种继承方式,但都不喜欢。然后我找到了一些有趣的东西。如果我们把 Date 和 DateTime 与 Integer 和 Float 进行比较呢?这似乎很合理,不是吗?DateTime 比Date更精确,Float 比Integer更精确。也许我错了,但据我所知,Float 和 Integer 之间没有继承关系。那么为什么 Date 和 DateTime 之间应该有呢?你可以这么说,也许 Float 和 Integer 之间不存在继承关系,但你可以在它们之间进行类型转换。这是正确的,你也可以在 Date 和 DateTime 之间进行类型转换。
new Date(DateTime::today()); new DateTime(Date::today());
DateRange & DateTimeRange 作为日期集合
大多数情况下,我们只需要一个DateTime对象,但有时我们需要更多彼此有一定距离的对象。为了避免创建一些令人讨厌的foreach循环,只需使用一个*Range对象即可。
$start = new DateTime('2014-08-01 08:00'); $end = new DateTime('2014-08-01-20:00'); $range = new DateTimeRange($start, $end, new DateInterval('PT1H'));
foreach($range as $datetime) { echo $datetime->format('Y-m-d H:i:s'); }
结果是
2014-08-01 08:00:00 2014-08-01 09:00:00 2014-08-01 10:00:00 2014-08-01 11:00:00 2014-08-01 12:00:00 2014-08-01 13:00:00 2014-08-01 14:00:00 2014-08-01 15:00:00 2014-08-01 16:00:00 2014-08-01 17:00:00 2014-08-01 18:00:00 2014-08-01 19:00:00 2014-08-01 20:00:00
您还可以使用工厂方法创建一个*Range对象。
/** For ranges that will hold five DateTime objects */ $start = new DateTime('2014-08-01 08:00'); DateTimeRange::from($start, 5, new DateInterval('PT1H'));
$end = new DateTime('2014-08-01 08:00'); DateTimeRange::to($end, 5, new DateInterval('PT1H'));
获取器 & 解析器
当前Joomla\Date中有些属性。您需要所有这些属性吗?真的吗?也许您还需要一些其他属性?也许您还需要一些解析方法?没问题,我可以为您添加3个更多属性,2个更多解析器和6个更多属性。到这周结束时,我们将拥有一个具有数百个属性和解析器的类。没有人会总是使用所有这些。我想表达的是:您需要的解析器和获取器强烈依赖于您的项目。不可能有人为所有情况提供所有属性。这是不可能完成的任务。我的解决方案:将整个属性和解析器功能移动到单独的类中,并提供一些定制方法。这就是Getter和Parser接口诞生的原因。
没有默认的解析器,因此如果您需要,您必须自己编写它。然而,有一个默认的获取器类,包含当前Date类中的所有属性,所以让我们从获取器开始。您可以通过显式调用get()方法或使用属性语法来获取属性。
$date->year == $date->get('year')
提供自定义获取器对象
我们需要两个新属性:一个用于日期,另一个用于时间。这是我们想要实现的目标。
$date->get('date'); $date->get('time');
让我们创建一个获取器类。为了提供默认功能,我们将使用装饰器模式。
class MyGetter implements Getter { /** @var Getter */ private $getter; public function __construct(Getter $getter) { $this->getter = $getter; } public function get(DateTime $datetime, $name) { switch($name) { case 'date': $value = $datetime->format('Y-m-d'); break; case 'time': $value = $datetime->format('H:i:s'); break; default: $value = $this->getter->get($datetime, $name); } return $value; } }
现在我们需要将我们的获取器对象注入到DateTime中。
DateTime::setGetter(new MyGetter(new DateTimeGetter()));
提供自定义解析器对象
为了提供新的解析器,我们还需要创建一个新的类。这里有两条途径:实现Parser接口或扩展AbstractParser类。在示例中,我们将使用第二种方法。
class MyParser extends AbstractParser
{
public function fromString($value)
{
return new DateTime($value);
} public function fromDate(Date $date)
{
return new DateTime($date);
}
public function fromPHPDateTime(\DateTime $datetime)
{
return new DateTime($datetime);
}
}
因为我们扩展了AbstractParser,所以可以在我们的解析器中创建任何需要的方法。我们还可以按自己的意愿调用它们。在这里命名很重要。
DateTime::setParser(new MyParser());
DateTime::parse('fromString', '2014-08-15');
DateTime::parse('fromDate', new Date());
DateTime::parse('fromPHPDateTime', new \DateTime());
我知道,这不是一个很有价值的解析器,因为我们可以在DateTime的构造函数中传递这些对象,我们不需要解析器。我只是想展示您如何轻松地扩展DateTime以适应您的需求。
关于GSoC的一些话
对我来说,这是一个美妙的夏天!我学到了很多关于PHP、SPL、PHPUnit、Composer等方面的知识。顺便说一句,如果您没有使用Composer来管理依赖项,您绝对应该尝试一下。它比PEAR好得多。毕竟,PEAR正在衰落。
在我为这个项目撰写提案之前,我对TDD和PHPUnit有一定的了解,但没有实际经验。现在我可以说我真的很喜欢TDD。也许它并不容易,但理念很简单,并对我帮助很大。也许它并不适合每个人,但首先您需要尝试它以获得自己的看法。对我来说,它非常有效,我几乎实现了98%的代码覆盖率。
这绝对不是我为JCM写的最后一篇文章(我已经承诺要写第二部分),但GSoC现在已经正式结束。我想感谢我的导师(Herman Peeren和Søren Beck Jensen)的支持。您非常有帮助。谢谢。希望很快能见到您!
在Joomla社区杂志上发表的一些文章代表了作者在特定主题上的个人观点或经验,可能并不与Joomla项目的官方立场一致。
通过接受,您将访问https://magazine.joomla.net.cn/外部第三方提供的服务
评论