日期包概览,第1部分
不幸的是,夏天结束了。让我们看看我是如何处理我们的全新日期包的GSoC项目的。
这就是结局
对我来说,这是一个美好的夏天,但遗憾的是,它结束得如此之快。我的主要目标是提供不可变的DateTime对象。任务完成!对我来说是个好消息,我希望对每个人来说也好。让我们快速看一下UML类图(在yuml.me上创建)
这里有很多内容,所以我需要向你解释一些。
为什么Joomla\DateTime\DateTime不扩展PHP DateTime?
PHP DateTime是可变的,我的主要目标是使DateTime类不可变。你可以在这里阅读更多关于它的内容here。更准确地说,我的目标是创建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)的支持。你们非常 helpful。谢谢。希望很快能见到你们!
在Joomla社区杂志上发表的一些文章代表了作者对特定主题的个人意见或经验,可能与Joomla项目的官方立场不一致。
通过接受,您将访问由 https://magazine.joomla.net.cn/ 外部的第三方提供的服务
评论