Skip to content

ext/intl: Add Transliterator::toRules() - #24384

Merged
LamentXU123 merged 1 commit into
php:masterfrom
LamentXU123:getrules
Oct 18, 2026
Merged

LamentXU123 merged 1 commit into
php:masterfrom
LamentXU123:getrules

Conversation

@LamentXU123

Copy link
Copy Markdown
Member

We have Transliterator::createFromRules(). And today I am quite surprised that we can't export a rule added by that in the PHP side. ICU have Transliterator::toRules() but we just forget to export it to PHP.

@LamentXU123 LamentXU123 changed the title ext/intl:Add Transliterator::toRules() ext/intl: Add Transliterator::toRules() Oct 17, 2026

TRANSLITERATOR_METHOD_FETCH_OBJECT;

int32_t rules_len = utrans_toRules(to->utrans, escape_unprintable, nullptr, 0,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about ?

diff --git a/ext/intl/transliterator/transliterator_methods.cpp b/ext/intl/transliterator/transliterator_methods.cpp
index 8b70219b11c..db92be76824 100644
--- a/ext/intl/transliterator/transliterator_methods.cpp
+++ b/ext/intl/transliterator/transliterator_methods.cpp
@@ -22,6 +22,8 @@
 #endif

 #include <unicode/uenum.h>
+#include <unicode/translit.h>
+#include "../intl_convertcpp.h"

 extern "C" {
 #include "php_intl.h"
@@ -235,26 +237,17 @@ U_CFUNC PHP_FUNCTION( transliterator_to_rules )

        TRANSLITERATOR_METHOD_FETCH_OBJECT;

-       int32_t rules_len = utrans_toRules(to->utrans, escape_unprintable, nullptr, 0,
-               TRANSLITERATOR_ERROR_CODE_P(to));
-       if (TRANSLITERATOR_ERROR_CODE(to) == U_BUFFER_OVERFLOW_ERROR) {
-               TRANSLITERATOR_ERROR_CODE(to) = U_ZERO_ERROR;
-       }
-       INTL_METHOD_CHECK_STATUS(to, "Failed to export transliterator rules");
-
-       int32_t capacity = rules_len < INT32_MAX ? rules_len + 1 : rules_len;
-       UChar *rules = reinterpret_cast<UChar *>(safe_emalloc(capacity, sizeof(UChar), 0));
-       rules_len = utrans_toRules(to->utrans, escape_unprintable, rules, capacity,
-               TRANSLITERATOR_ERROR_CODE_P(to));
-       if (U_FAILURE(TRANSLITERATOR_ERROR_CODE(to))) {
-               efree(rules);
+       UnicodeString rules;
+       reinterpret_cast<const icu::Transliterator *>(to->utrans)->tble);
+
+       zend_string *u8str = intl_charFromString(rules, TRANSLITERAT
+       if (!u8str) {
+               if (U_SUCCESS(TRANSLITERATOR_ERROR_CODE(to))) {
+                       TRANSLITERATOR_ERROR_CODE(to) = U_MEMORY_ALLOCATION_ERROR;
+               }
                INTL_METHOD_CHECK_STATUS(to, "Failed to export transliterator rules");
        }
-       if (TRANSLITERATOR_ERROR_CODE(to) == U_STRING_NOT_TERMINATED_WARNING) {
-               TRANSLITERATOR_ERROR_CODE(to) = U_ZERO_ERROR;
-       }
-
-       INTL_METHOD_RETVAL_UTF8(to, rules, rules_len, 1);
+       RETURN_STR(u8str);
 }
 /* }}} */

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't see that API before :)

Expose transliterator rules through Transliterator::toRules() and
transliterator_to_rules(), with optional escaping of unprintable characters.
Use ICU's C++ API to export the rules into a UnicodeString.

Co-authored-by: David Carlier <devnexen@gmail.com>
@LamentXU123
LamentXU123 merged commit f0e88c7 into php:master Oct 18, 2026
16 of 18 checks passed
@LamentXU123

Copy link
Copy Markdown
Member Author

Thanks!

@LamentXU123
LamentXU123 deleted the getrules branch October 18, 2026 09:49
reinterpret_cast<const icu::Transliterator *>(to->utrans)->toRules(rules, escape_unprintable);

zend_string *u8str = intl_charFromString(rules, TRANSLITERATOR_ERROR_CODE_P(to));
if (!u8str) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question about this error path:
This runs if u8str is a NULL pointer, yet the execution of this branch doesn't stop after INTL_METHOD_CHECK_STATUS, which means that RETURN_STR(NULL) will be executed.
That's not legal. What am I missing?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah god, it's a macro that returns (conditionally) false... I see

@LamentXU123 LamentXU123 Oct 18, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its better to set error message explictly and RETURN_FALSE; ... wdyt?
I mean as a refactor to the code base.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind per se that the macro returns, but the name should make that clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants