Hi
On 2026-08-07 20:46, Weilin Du wrote:
For enums and namespaces: I kept class constants and the global Intl*
class name to stay
consistent with the existing ext/intl API, such as IntlDateFormatter,
IntlListFormatter
IntlNumberRangeFormatter, and IntlDatePatternGenerator. I don't want to
make
IntlRelativeDateTimeFormatter somehow special here just because this is
added later.
I agree that enums and namespaces would be nicer in isolation,
*indeed*. But,
introducing them for only this one formatter would make the API
inconsistent with the rest
of ext/intl.
As I had mentioned in the voting thread, I think there is a reasonable
middleground to be achieved here:
final class IntlRelativeDateTimeFormatter
{
public function __construct(
?string $locale = null,
IntlRelativeDateTimeFormatterStyle $style =
IntlRelativeDateTimeFormatterStyle::Long,
IntlRelativeDateTimeFormatterCapitalization
$capitalizationContext =
IntlRelativeDateTimeFormatterCapitalization::None,
?NumberFormatter $numberFormatter = null,
) {}
public function format(int|float $offset,
IntlRelativeDateTimeFormatterUnit $unit): string|false {}
public function formatNumeric(int|float $offset, int $unit):
string|false {}
public function combineDateAndTime(string $relativeDate, string
$time): string|false {}
public function getErrorCode(): int {}
public function getErrorMessage(): string {}
}
enum IntlRelativeDateTimeFormatterStyle {
case Long;
case Short;
case Narrow;
}
enum IntlRelativeDateTimeFormatterCapitalization {
case None;
case MiddleOfSentence;
case BeginningOfSentence;
case UiListAndMenu;
case Standalone;
}
enum IntlRelativeDateTimeFormatterUnit {
case Year;
case Quarter;
case Month;
case Week;
case Day;
case Hour;
case Minute;
case Second;
// ...
}
The practical change for the users is just moving some separators
around:
$formatter->format(-1, IntlRelativeDateTimeFormatter::UNIT_DAY)
// becomes
$formatter->format(-1, IntlRelativeDateTimeFormatterUnit::Day)
Basically the first component of the constant name moves in front of the
`::` (and underscores are replaced by pascal case).
No namespaces are introduced, leaving a clean place for a redesigned
Intl API that doesn't just expose the ICU API as-is, but the main
benefits of using enums are preserved: Better discoverability and
autocompletion in IDEs. Cleaner documentation (it's possible to document
both the enum and the individual cases). Simplified input checks in the
internal implementation (error handling is implicitly provided by the
engine with the Z_PARAM_ENUM specifier).
I believe that users will value the clearer API signatures provided by
enums over the tiny inconsistency of placing the “Unit”, “Style” and
“Capitalization” in front of the `::` instead of after - and enums
themselves are already used in PHP’s stdlib (e.g. RoundingMode), so
users have already encountered them.
Best regards
Tim Düsterhus