-
-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New feature: split() with backwards option #53
Conversation
@bpolaszek I'll be straightforward ... I like the idea ... but I hate the implementation :) . From past experiences, I don't like boolean argument a previous version of Period had a getInterval methid which took a boolean argument to switch the method return value and I hate that because when in use you are force at some point in time to go back into the documentation to be sure about the behavior of a boolean argument. Having said that, if you look at the code you discover that |
Hi @nyamsprod, Could not agree more :) I did this ugly implementation in order to avoid BC breaks (since the class is not final, we should avoid adding new methods - but I just realized @Ocramius made me paranoid), but I definitely prefer the use of 2 methods. At first I thought about renaming Now, after reading your answer, I definitely think we need 2 different methods for this evolution, but I think renaming
Besides, I don't think a So, here's what I suggest (what I should have done from the beginning): /**
* @param $interval
* @return Generator|Period[]
*/
public function split($interval)
{
$startDate = $this->startDate;
$interval = static::filterDateInterval($interval);
do {
$endDate = $startDate->add($interval);
if ($endDate > $this->endDate) {
$endDate = $this->endDate;
}
yield new static($startDate, $endDate);
$startDate = $endDate;
} while ($startDate < $this->endDate);
}
/**
* @param $interval
* @return Generator|Period[]
*/
public function splitBackwards($interval)
{
$endDate = $this->endDate;
$interval = static::filterDateInterval($interval);
do {
$startDate = $endDate->sub($interval);
if ($startDate < $this->startDate) {
$startDate = $this->startDate;
}
yield new static($startDate, $endDate);
$endDate = $startDate;
} while ($endDate > $this->startDate);
} This way the original What do you think? |
src/Period.php
Outdated
} else { | ||
$endDate = $this->endDate; | ||
$interval = static::filterDateInterval($interval); | ||
do { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block is repeated in both conditionals, but with changed variables - can simply move to a private method
src/Period.php
Outdated
* | ||
* @return Generator|Period[] | ||
*/ | ||
public function split($interval) | ||
public function split($interval, $backwards = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?bool
? Does this library provide PHP 7.1-only support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not a second method splitBackwards
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ocramius this is what I have suggested @bpolaszek to do 👍
@bpolaszek you don't need to renamed split ... just add splitBackward and you'll be done |
@Ocramius there's another PR I've been working on to release a new version which will require 7.1+ |
@bpolaszek AFAIK adding a new method does not constitute a BC break :) and the Period class is no longer final since version 3 |
That kinda makes it a BC break for child classes, although mild. New method not being overridden => bug. |
Here it is. |
Thank you @nyamsprod! 🎉 |
@bpolaszek I'll try to release a 3.4.0 in the next couple of days ... but I think it will be the last release in the current v3 version. I'll backport your method in the new v4 version. Also If you are interested I've opened an issue where I'm collecting comments and suggestion for the v4 version #54 I would appreciate your opinion on this |
@nyamsprod That's a good idea. But I must admit I'm pretty new to immutability in the PHP world (apart from Period, DateTimeImmutable and PSR-7 objects that I know how to use, I do not currently master all the pros and the cons between final and non-final), so I prefer to remain quiet on this topic. I just noticed you've got a Lines 856 to 869 in 28f2834
I suggest type-hinting a more generic public function split($interval): iterable
{
$interval = static::filterDateInterval($interval);
return new class($this, $interval) implements \IteratorAggregate, \Countable
{
private $period;
private $className;
private $interval;
public function __construct(Period $period, DateInterval $interval)
{
$this->period = $period;
$this->className = get_class($period);
$this->interval = $interval;
}
public function getIterator(): iterable
{
$className = $this->className;
$startDate = $this->period->getStartDate();
do {
$endDate = $startDate->add($this->interval);
if ($endDate > $this->period->getEndDate()) {
$endDate = $this->period->getEndDate();
}
yield new $className($startDate, $endDate);
$startDate = $endDate;
} while ($startDate < $this->period->getEndDate());
}
/**
* The goal is to count faster than iterator_count()
* There's surely a more efficient way to do this
*/
public function count(): int
{
$cnt = 0;
$current = DateTime::createFromFormat('U', (string) $this->period->getStartDate()->getTimestamp());
$end = $this->period->getEndDate();
while ($current < $end) {
$cnt++;
$current->add($this->interval);
}
return $cnt;
}
};
}
// ...
$period = Period::createFromDuration(new DateTime('2015-01-01'), '3 years');
$split = $period->split('1 hour');
$numberOfHours = count($split);
var_dump($numberOfHours); // == 26304 - we didn't even need to instanciate new Period objects
if ($numberOfHours < 20000) {
foreach ($split as $subPeriod) {
// there we go
}
} What do you think? |
@bpolaszek yes the Generator type hint is an old addition .. the PHP7-only branch is very old I did not have time to work on it 👍 and since I will push for a PHP7.1+ requirement I'll use the iterable typehint instead ... when this PR was started iterable did not exist yet and I was targeting PHP7.0 |
I've already added splitBackwards to the branch on my local machine 👍 |
Great - nothing to add :) Thanks! 🍻 |
Introduction
This PR enables an optionnal backwards feature on the
split()
method.Proposal
Describe the new/updated/fixed feature
When set to
true
(defaults tofalse
to keep BC), thesplit()
method will start to yield periods from the most recent one.Backward Incompatible Changes
Nope, maybe excepted for developers who overrid the class and changed that method signature already.
Targeted release version
Next minor version.