Commit 371d460a3c3 for php
commit 371d460a3c3e6beacaf21321955b7da97aafeb4f
Author: Weilin Du <weilindu@php.net>
Date: Sun Nov 8 01:26:01 2026 +0800
ext/intl: Implement Collator::getRules() (#25222)
This expose ucol_getRules to userland as Collator::getRules().
diff --git a/NEWS b/NEWS
index 30fdbb91de1..81a3b5ebd55 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,7 @@ PHP NEWS
throwing a ValueError. (Marc Bennewitz)
- Intl:
+ . Added Collator::getRules() and collator_get_rules(). (Weilin Du)
. Added IntlRelativeDateTimeFormatter for locale-aware relative date and time
formatting, with enums for styles, capitalization contexts, and units.
(Weilin Du)
diff --git a/UPGRADING b/UPGRADING
index d91fda65368..3867497fa9c 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -124,6 +124,11 @@ PHP 8.7 UPGRADE NOTES
. Added Transliterator::toRules() and transliterator_to_rules() to export
rules that can be used to recreate a transliterator. The optional
$escapeUnprintable argument escapes unprintable characters when true.
+ . Added Collator::getRules() and collator_get_rules() to retrieve collation
+ tailoring rules as a UTF-8 string. These describe locale-specific adjustments
+ to the root collation order; the full root/UCA rules are not included. An
+ empty string is returned if no tailoring rules are available, or false if
+ the rules cannot be converted to UTF-8.
========================================
7. New Classes and Interfaces
diff --git a/ext/intl/collator/collator.stub.php b/ext/intl/collator/collator.stub.php
index e41684c691e..f6f465ede69 100644
--- a/ext/intl/collator/collator.stub.php
+++ b/ext/intl/collator/collator.stub.php
@@ -137,6 +137,9 @@ public function setStrength(int $strength): true {}
*/
public function getLocale(int $type): string|false {}
+ /** @alias collator_get_rules */
+ public function getRules(): string|false {}
+
/**
* @tentative-return-type
* @alias collator_get_error_code
diff --git a/ext/intl/collator/collator_arginfo.h b/ext/intl/collator/collator_arginfo.h
index bf8345cd8be..837249cb9ed 100644
Binary files a/ext/intl/collator/collator_arginfo.h and b/ext/intl/collator/collator_arginfo.h differ
diff --git a/ext/intl/collator/collator_locale.cpp b/ext/intl/collator/collator_locale.cpp
index 2d346f439c9..d09dba29a0a 100644
--- a/ext/intl/collator/collator_locale.cpp
+++ b/ext/intl/collator/collator_locale.cpp
@@ -59,3 +59,28 @@ U_CFUNC PHP_FUNCTION( collator_get_locale )
RETVAL_STRINGL( locale_name, strlen(locale_name) );
}
/* }}} */
+
+/* {{{ Gets the collation tailoring rules. */
+U_CFUNC PHP_FUNCTION(collator_get_rules)
+{
+ COLLATOR_METHOD_INIT_VARS
+
+ if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O",
+ &object, Collator_ce_ptr) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ if (collator_check_initialized(co) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ int32_t rules_len;
+ const UChar *rules = ucol_getRules(co->ucoll, &rules_len);
+ zend_string *result = intl_convert_utf16_to_utf8(rules, rules_len, COLLATOR_ERROR_CODE_P(co));
+ COLLATOR_CHECK_STATUS(co, "Error converting collation rules to UTF-8");
+
+ RETURN_STR(result);
+}
+/* }}} */
diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php
index a6a519e50f6..e132a4f670c 100644
--- a/ext/intl/php_intl.stub.php
+++ b/ext/intl/php_intl.stub.php
@@ -308,6 +308,8 @@ function collator_asort(Collator $object, array &$array, int $flags = Collator::
function collator_get_locale(Collator $object, int $type): string|false {}
+function collator_get_rules(Collator $object): string|false {}
+
function collator_get_error_code(Collator $object): int|false {}
function collator_get_error_message(Collator $object): string|false {}
diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h
index a1b95671d27..a360a0be99e 100644
Binary files a/ext/intl/php_intl_arginfo.h and b/ext/intl/php_intl_arginfo.h differ
diff --git a/ext/intl/tests/collator_get_rules.phpt b/ext/intl/tests/collator_get_rules.phpt
new file mode 100644
index 00000000000..b23af2cc622
--- /dev/null
+++ b/ext/intl/tests/collator_get_rules.phpt
@@ -0,0 +1,26 @@
+--TEST--
+Collator::getRules() returns collation tailoring rules as UTF-8
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+$root = new Collator('root');
+var_dump($root->getRules());
+var_dump(collator_get_rules($root));
+
+$collator = new Collator('de_DE@collation=phonebook');
+$rules = $collator->getRules();
+var_dump(is_string($rules) && $rules !== '');
+var_dump(preg_match('/\x{00E4}/u', $rules));
+var_dump(collator_get_rules($collator) === $rules);
+
+unset($collator);
+var_dump(preg_match('/\x{00E4}/u', $rules));
+?>
+--EXPECT--
+string(0) ""
+string(0) ""
+bool(true)
+int(1)
+bool(true)
+int(1)
diff --git a/ext/intl/tests/collator_get_rules_error.phpt b/ext/intl/tests/collator_get_rules_error.phpt
new file mode 100644
index 00000000000..121b8fa0de8
--- /dev/null
+++ b/ext/intl/tests/collator_get_rules_error.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Collator::getRules() resets errors and rejects unconstructed objects
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+class UnconstructedCollator extends Collator {
+ public function __construct() {}
+}
+
+foreach ([fn($c) => $c->getRules(), collator_get_rules(...)] as $getRules) {
+ $collator = new Collator('root');
+ var_dump($collator->getAttribute(-1));
+ var_dump(intl_get_error_code() === U_ILLEGAL_ARGUMENT_ERROR);
+ var_dump($getRules($collator));
+ var_dump(intl_get_error_message());
+ var_dump($collator->getErrorMessage());
+
+ try {
+ $getRules(new UnconstructedCollator());
+ } catch (Error $e) {
+ echo $e->getMessage(), "\n";
+ }
+}
+?>
+--EXPECT--
+bool(false)
+bool(true)
+string(0) ""
+string(12) "U_ZERO_ERROR"
+string(12) "U_ZERO_ERROR"
+Object not initialized
+bool(false)
+bool(true)
+string(0) ""
+string(12) "U_ZERO_ERROR"
+string(12) "U_ZERO_ERROR"
+Object not initialized