3v4l.org

run code in 300+ PHP versions simultaneously
<?php declare(strict_types = 1); /** * https://github.com/ekinhbayar/IntervalParser/ */ namespace IntervalParser; use \DateInterval; class Exception extends \Exception {} class FormatException extends Exception {} class IntervalIterator implements \Iterator { private $var = []; public function __construct($array) { if (is_array($array)) { $this->var = $array; } } public function rewind() { #echo "rewinding\n"; reset($this->var); } public function current() { $var = current($this->var); # echo "current: $var\n"; return $var; } public function key() { $var = key($this->var); #echo "key: $var\n"; return $var; } public function next() { $var = next($this->var); #echo "next: $var\n"; return $var; } public function valid() { $key = key($this->var); $var = ($key !== NULL && $key !== FALSE); #echo "valid: $var\n"; return $var; } } /** Parser Settings * * IntervalParser takes a ParserSettings object which is handy for when you want to deal with multiple intervals. * * When parsing multiple intervals if you don't supply your own settings, * the parser will try to find comma separated intervals within given input by default. * However there is no default value for $wordSeparator. * * Example: * * $parserSettings = new ParserSettings(',', 'then'); * # works for "2 days then 5 months then 2 hours" * $intervalParser = new IntervalParser($parserSettings); * */ class ParserSettings { const SYMBOL = 0; const STRING = 1; private $separationType; private $symbol; private $word; /** * ParserSettings constructor. * * @param int $separationType * @param string $symbol * @param string|null $word */ public function __construct( int $separationType = self::SYMBOL, string $symbol = ',', string $word = null ) { $this->separationType = $separationType; $this->word = $word; $this->symbol = $symbol; } public function getSymbolSeparator() : string { return $this->symbol; } public function getWordSeparator() : string { return $this->word; } public function getSeparationType(): string { return ($this->separationType == self::STRING) ? 'string' : 'symbol'; } } class IntervalFlags { const INTERVAL_ONLY = 0b00000000; const REQUIRE_TRAILING = 0b00000001; const REQUIRE_LEADING = 0b00000010; const MULTIPLE_INTERVALS = 0b00000100; } class TimeInterval { private $intervalOffset; private $intervalLength; /*private $intervalType;*/ private $leadingData; private $trailingData; private $interval; public function __construct( int $intervalOffset, int $intervalLength, /*int $intervalType,*/ string $leadingData = null, string $trailingData = null, DateInterval $interval ) { $this->interval = $interval; $this->intervalOffset = $intervalOffset; $this->intervalLength = $intervalLength; /*$this->intervalType = $intervalType;*/ $this->leadingData = $leadingData; $this->trailingData = $trailingData; } public function getInterval() : DateInterval { return $this->interval; } public function getIntervalOffset() : int { return $this->intervalOffset; } public function getIntervalLength() : int { return $this->intervalLength; } /*public function getIntervalType() : int { return $this->intervalType; }*/ public function getLeadingData() : string { return $this->leadingData; } public function getTrailingData() : string { return $this->trailingData; } } class IntervalParser { /** * Set of regular expressions utilized to match/replace/validate parts of a given input. * * Don't forget to close parentheses when using $define */ public static $define = "/(?(DEFINE)"; # Definitions of sub patterns for a valid interval public static $integer = <<<'REGEX' (?<integer> (?:\G|(?!\n)) (\s*\b)? \d{1,5} \s* ) REGEX; # Starts with integer followed by time specified public static $timepart = <<<'REGEX' (?<timepart> (?&integer) ( s(ec(ond)?s?)? | m(on(ths?)?|in(ute)?s?)? | h(rs?|ours?)? | d(ays?)? | w(eeks?)? ) ) REGEX; # Leading separator public static $leadingSeparator = "(?<leadingSeparator>\s?(?:in)\s?)"; # Leading separator with capturing groups public static $leadingGroupSeparator = "/(.*)\s+(?:in)\s+(.*)/ui"; # Regex to match a valid interval, holds the value in $matches['interval'] public static $intervalOnly = "^(?<interval>(?&timepart)++)$/uix"; # Regex to match a valid interval and any trailing string, holds the interval in $matches['interval'], the rest in $matches['trailing'] public static $intervalWithTrailingData = "^(?<interval>(?&timepart)++)(?<trailing>.+)*?$/uix"; /** * Used to turn a given non-strtotime-compatible time string into a compatible one * Only modifies the non-strtotime-compatible time strings provided leaving the rest intact * * @var string $normalizerExpression */ public static $normalizerExpression = <<<'REGEX' ~ # grab the integer part of time string \s? (?<int> \d{1,5}) \s? # match only the shortest abbreviations that aren't supported by strtotime (?<time> (?: s (?=(?:ec(?:ond)?s?)?(?:\b|\d)) | m (?=(?:in(?:ute)?s?)?(?:\b|\d)) | h (?=(?:(?:ou)?rs?)?(?:\b|\d)) | d (?=(?:ays?)?(?:\b|\d)) | w (?=(?:eeks?)?(?:\b|\d)) | mon (?=(?:(?:th)?s?)?(?:\b|\d)) ) ) [^\d]*?(?=\b|\d) # do only extract start of string | (?<text> .+) ~uix REGEX; # Regex to handle an input that may have multiple intervals along with leading and/or trailing data public static $multipleIntervals = <<<'REGEX' ^(?<leading>.*?)? (?<sep>(?&leadingSeparator))? (?<interval>(?&timepart)++) (?<trailing>.*) /uix REGEX; /** * IntervalParser constructor. * * Default settings are : * * string $symbolSeparator = ',', * string $wordSeparator = null * * @param \IntervalParser\ParserSettings $settings */ public function __construct(ParserSettings $settings) { $this->settings = $settings; } /** * Looks for a valid interval along with leading and/or trailing data IF the respective flags are set. * TimeInterval is essentially DateInterval with extra information such as interval offset & length, leading/trailing data. * * @param string $input * @param int $flags * @return TimeInterval|array * @throws FormatException */ public function findInterval(string $input, int $flags = IntervalFlags::INTERVAL_ONLY) { if( $flags & ~IntervalFlags::INTERVAL_ONLY & ~IntervalFlags::REQUIRE_TRAILING & ~IntervalFlags::REQUIRE_LEADING & ~IntervalFlags::MULTIPLE_INTERVALS ){ throw new InvalidFlagException("You have tried to use an invalid flag combination."); } if($flags & IntervalFlags::INTERVAL_ONLY){ $input = $this->normalizeTimeInterval($input); $definition = self::$define . self::$integer . self::$timepart .')'; $expression = $definition . self::$intervalOnly; if(preg_match($expression, $input)){ $intervalOffset = 0; $intervalLength = strlen($input); # create and return the interval object $interval = DateInterval::createFromDateString($input); return new TimeInterval($intervalOffset, $intervalLength, null, null, $interval); } throw new FormatException("Given input is not a valid interval."); } if($flags == (IntervalFlags::REQUIRE_LEADING | IntervalFlags::REQUIRE_TRAILING)){ # Default leading separator is "in" $leadingSeparation = preg_match(self::$leadingGroupSeparator, $input, $matches, PREG_OFFSET_CAPTURE); if(!$leadingSeparation){ throw new FormatException("Allowing leading data requires using a separator. Ie. foo in <interval>"); } $leadingData = $matches[1][0] ?? null; $intervalAndTrailingData = $matches[2][0] ?? null; # throw early for missing parts if(!$leadingData){ throw new FormatException("Given input does not contain a valid leading data."); } if(!$intervalAndTrailingData){ throw new FormatException("Given input does not contain a valid interval and/or trailing data."); } $intervalOffset = $matches[2][1] ?? null; # If interval contains non-strtotime-compatible abbreviations, replace 'em $intervalAndTrailingData = $this->normalizeTimeInterval($intervalAndTrailingData); $definition = self::$define . self::$integer . self::$timepart .')'; $expression = $definition . self::$intervalWithTrailingData; if(preg_match($expression, $intervalAndTrailingData, $parts)){ $interval = $parts['interval']; $trailingData = $parts['trailing']; $intervalLength = strlen($interval); # create and return the interval object $interval = DateInterval::createFromDateString($interval); return new TimeInterval($intervalOffset, $intervalLength, $leadingData, $trailingData, $interval); } throw new FormatException("Given input does not contain a valid interval and/or trailing data."); } if($flags & IntervalFlags::REQUIRE_LEADING){ # Default leading separator is "in" $leadingSeparation = preg_match(self::$leadingGroupSeparator, $input, $matches, PREG_OFFSET_CAPTURE); if(!$leadingSeparation){ throw new FormatException("Allowing leading data requires using a separator. Ie. foo in <interval>"); } $leadingData = $matches[1][0] ?? null; $intervalAndPossibleTrailingData = $matches[2][0] ?? null; if(!$leadingData){ throw new FormatException("Could not find any valid leading data."); } if(!$intervalAndPossibleTrailingData){ throw new FormatException("Could not find any valid interval and/or leading data."); } $intervalOffset = $matches[2][1] ?? null; # If interval contains non-strtotime-compatible abbreviations, replace 'em $safeInterval = $this->normalizeTimeInterval($intervalAndPossibleTrailingData); # since above normalization is expected to not return any trailing data, only check for a valid interval $definition = self::$define . self::$integer . self::$timepart .')'; $expression = $definition . self::$intervalOnly; if(preg_match($expression, $safeInterval, $parts)){ $interval = $parts['interval']; $intervalLength = strlen($interval); # create the interval object $interval = DateInterval::createFromDateString($interval); return new TimeInterval($intervalOffset, $intervalLength, $leadingData, null, $interval); } throw new FormatException("Given input does not contain a valid interval. Keep in mind trailing data is not allowed with current flag."); } if($flags & IntervalFlags::REQUIRE_TRAILING){ $definition = self::$define . self::$integer . self::$timepart .')'; $expression = $definition . self::$intervalWithTrailingData; # If interval contains non-strtotime-compatible abbreviations, replace 'em $safeInterval = $this->normalizeTimeInterval($input); # Separate interval from trailing data if(preg_match($expression, $safeInterval, $parts)){ $trailingData = $parts['trailing'] ?? null; $interval = $parts['interval'] ?? null; if(!$interval){ throw new FormatException("Could not find any valid interval."); } if(!$trailingData){ throw new FormatException("Could not find any valid trailing data."); } $intervalLength = strlen($interval); $intervalOffset = 0; # since we don't allow leading data here # create the interval object $interval = DateInterval::createFromDateString($interval); return new TimeInterval($intervalOffset, $intervalLength, null, $trailingData, $interval); } throw new FormatException("Given input does not contain a valid interval. Keep in mind leading data is not allowed with current flag."); } if($flags & IntervalFlags::MULTIPLE_INTERVALS){ $payload = []; $separator = ($this->settings->getSeparationType() == 'symbol') ? $this->settings->getSymbolSeparator() : $this->settings->getWordSeparator(); $expression = "/(?J)\b(?:(?<match>.*?)\s?{$separator})\s?|\b(?<match>.*)/ui"; if(preg_match_all($expression, $input, $intervals, PREG_SET_ORDER)){ $intervalSet = array_filter(array_map(function($set){ foreach($iter = new IntervalIterator($set) as $key => $interval){ if($iter->key() === 'match') { return $interval; } } }, $intervals)); foreach($intervalSet as $key => $interval){ $definition = self::$define . self::$leadingSeparator . self::$integer . self::$timepart .')'; $expression = $definition . self::$multipleIntervals; preg_match($expression, $interval, $matches); $matches = array_filter($matches); $leadingData = $matches['leading'] ?? null; $leadingSep = $matches['sep'] ?? false; $interval = $matches['interval'] ?? null; $trailing = $matches['trailing'] ?? null; if(!$leadingData){ $leadingData = ($leadingSep) ?: ""; } $intervalOffset = (!$leadingSep) ? 0 : strlen($leadingData) + strlen($leadingSep); # If interval contains non-strtotime-compatible abbreviations, replace them $safeInterval = $this->normalizeTimeInterval($interval . $trailing); # Separate intervals from trailing data if(preg_match($expression, $safeInterval, $parts)){ $trailingData = $parts['trailing'] ?? null; $interval = $parts['interval'] ?? null; if(!$interval) continue; $intervalLength = strlen($interval); # create the interval object $interval = DateInterval::createFromDateString($interval); $payload[] = new TimeInterval($intervalOffset, $intervalLength, $leadingData, $trailingData, $interval); } } if($payload) return $payload; } } } /** * Turns any non-strtotime-compatible time string into a compatible one. * If the passed input has trailing data, it won't be lost since within the callback the input is reassembled. * However no leading data is accepted. * * @param string $input * @return string */ public function normalizeTimeInterval(string $input): string { $output = preg_replace_callback(self::$normalizerExpression, function ($matches) { $int = $matches['int']; switch ($matches['time']) { case 's': $t = ($int == 1) ? ' second ' : ' seconds '; break; case 'm': $t = ($int == 1) ? ' minute ' : ' minutes '; break; case 'h': $t = ($int == 1) ? ' hour ' : ' hours '; break; case 'd': $t = ($int == 1) ? ' day ' : ' days '; break; case 'w': $t = ($int == 1) ? ' week ' : ' weeks '; break; case 'mon': $t = ($int == 1) ? ' month ' : ' months '; break; case 'y': $t = ($int == 1) ? ' year ' : ' years '; break; } $t = $t ?? ''; # rebuild the interval string $time = $int . $t; if(isset($matches['text'])){ $time .= trim($matches['text']); } return $time; }, $input); return trim($output); } /** * Normalizes any non-strtotime-compatible time string, then validates the interval and returns a DateInterval object. * No leading or trailing data is accepted. * * @param string $input * @return DateInterval * @throws \InvalidArgumentException */ public function parseInterval(string $input): \DateInterval { $input = trim($this->normalizeTimeInterval($input)); $definition = self::$define . self::$integer . self::$timepart .')'; $expression = $definition . self::$intervalOnly; if(preg_match($expression, $input, $matches)){ return DateInterval::createFromDateString($input); } throw new FormatException("Given string is not a valid time interval."); } } # Set ParserSettings for IntervalParser $settings1 = new ParserSettings(); $settings2 = new ParserSettings(0); $settings3 = new ParserSettings(1, ',', 'then'); $settings4 = new ParserSettings(0, '-'); $intervalParser1 = new IntervalParser($settings1); $intervalParser2 = new IntervalParser($settings2); $intervalParser3 = new IntervalParser($settings3); $intervalParser4 = new IntervalParser($settings4); // Usage # Only interval & trailing data $trailingString = '7mon6w5d4h3m2s bazinga!'; #$timeIntervalWithTrailingData = $intervalParser->findInterval($trailingString, IntervalFlags::REQUIRE_TRAILING); #var_dump($timeIntervalWithTrailingData); # Only leading data & interval $leadingString = 'foo in 9w8d7h6m5s'; #$timeIntervalWithLeadingData = $intervalParser->findInterval($leadingString, IntervalFlags::REQUIRE_LEADING); #var_dump($timeIntervalWithLeadingData); # Both interval & leading & trailing data $both = 'foo in 9d8h5m bar'; #$timeIntervalWithBoth = $intervalParser->findInterval($both, IntervalFlags::REQUIRE_TRAILING | IntervalFlags::REQUIRE_LEADING); #var_dump($timeIntervalWithBoth); # Only interval $onlyInterval = '9 mon 2 w 3 m 4 d'; #$dateInterval = $intervalParser->parseInterval($onlyInterval); #var_dump($dateInterval); #$normalizedInterval = $intervalParser->normalizeTimeInterval($onlyInterval); #var_dump($normalizedInterval); # Multiple Intervals # 1. Comma Separated $multiple = 'foo in 9d8h5m bar , baz in 5 minutes, foo in 2 days 4 minutes boo, in 1 hr, 10 days'; $multipleWithSymbol = 'foo in 9d8h5m bar - baz in 5 minutes- foo in 2 days 4 minutes boo- in 1 hr- 10 days'; $multipleWithWord = 'foo in 9d8h5m bar then baz in 5 minutes then foo in 2 days 4 minutes boo then in 1 hr then 10 days'; $multipleIntervals = $intervalParser1->findInterval($multiple, IntervalFlags::MULTIPLE_INTERVALS); var_dump($multipleIntervals); # 2. Separated by a defined-on-settings word #$wordSeparated = 'foo in 9d8h5m bar then baz in 5 minutes then foo in 2 days 4 minutes boo then in 2 hours'; #$wordSeparatedIntervals = $intervalParser3->findInterval($wordSeparated, IntervalFlags::MULTIPLE_INTERVALS); #var_dump($wordSeparatedIntervals);
Output for 7.1.0 - 7.1.33, 7.2.0 - 7.2.33, 7.3.0 - 7.3.30, 7.4.0 - 7.4.24, 8.0.0 - 8.0.11
array(5) { [0]=> object(IntervalParser\TimeInterval)#10 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(7) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(24) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "foo" ["trailingData":"IntervalParser\TimeInterval":private]=> string(4) " bar" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#9 (16) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(9) ["h"]=> int(8) ["i"]=> int(5) ["s"]=> int(0) ["f"]=> float(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [1]=> object(IntervalParser\TimeInterval)#12 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(7) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(9) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "baz" ["trailingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#11 (16) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(0) ["h"]=> int(0) ["i"]=> int(5) ["s"]=> int(0) ["f"]=> float(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [2]=> object(IntervalParser\TimeInterval)#14 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(7) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(16) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "foo" ["trailingData":"IntervalParser\TimeInterval":private]=> string(4) " boo" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#13 (16) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(2) ["h"]=> int(0) ["i"]=> int(4) ["s"]=> int(0) ["f"]=> float(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [3]=> object(IntervalParser\TimeInterval)#16 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(6) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(6) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "in " ["trailingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#15 (16) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(0) ["h"]=> int(1) ["i"]=> int(0) ["s"]=> int(0) ["f"]=> float(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [4]=> object(IntervalParser\TimeInterval)#18 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(0) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(7) ["leadingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["trailingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#17 (16) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(10) ["h"]=> int(0) ["i"]=> int(0) ["s"]=> int(0) ["f"]=> float(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } }
Output for 7.0.0 - 7.0.33
array(5) { [0]=> object(IntervalParser\TimeInterval)#10 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(7) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(24) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "foo" ["trailingData":"IntervalParser\TimeInterval":private]=> string(4) " bar" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#9 (15) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(9) ["h"]=> int(8) ["i"]=> int(5) ["s"]=> int(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [1]=> object(IntervalParser\TimeInterval)#12 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(7) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(9) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "baz" ["trailingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#11 (15) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(0) ["h"]=> int(0) ["i"]=> int(5) ["s"]=> int(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [2]=> object(IntervalParser\TimeInterval)#14 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(7) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(16) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "foo" ["trailingData":"IntervalParser\TimeInterval":private]=> string(4) " boo" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#13 (15) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(2) ["h"]=> int(0) ["i"]=> int(4) ["s"]=> int(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [3]=> object(IntervalParser\TimeInterval)#16 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(6) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(6) ["leadingData":"IntervalParser\TimeInterval":private]=> string(3) "in " ["trailingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#15 (15) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(0) ["h"]=> int(1) ["i"]=> int(0) ["s"]=> int(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } [4]=> object(IntervalParser\TimeInterval)#18 (5) { ["intervalOffset":"IntervalParser\TimeInterval":private]=> int(0) ["intervalLength":"IntervalParser\TimeInterval":private]=> int(7) ["leadingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["trailingData":"IntervalParser\TimeInterval":private]=> string(0) "" ["interval":"IntervalParser\TimeInterval":private]=> object(DateInterval)#17 (15) { ["y"]=> int(0) ["m"]=> int(0) ["d"]=> int(10) ["h"]=> int(0) ["i"]=> int(0) ["s"]=> int(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> bool(false) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) } } }
Output for 5.6.4 - 5.6.40
Warning: Unsupported declare 'strict_types' in /in/T5qBt on line 1 Fatal error: Default value for parameters with a class type hint can only be NULL in /in/T5qBt on line 94
Process exited with code 255.
Output for 5.6.0 - 5.6.3
Warning: Unsupported declare 'strict_types' in /in/T5qBt on line 1 Fatal error: Default value for parameters with a class type hint can only be NULL in /in/T5qBt on line 93
Process exited with code 255.

preferences:
188.99 ms | 401 KiB | 206 Q