====== PHP RFC: grapheme_str_pad ====== * Version: 0.1 * Date: 2026-11-03 * Author: Chris Abner Herrera Navarro, chrisabner@hotmail.com * Status: Under Discussion * Target Version: PHP 8.7 * Implementation: https://github.com/php/php-src/pull/25179 * Discussion thread: https://news-web.php.net/php.internals/132995 * Voting thread: TBD ===== Introduction ===== PHP has a padding function for bytes, ''str_pad()'', and one for code points, ''mb_str_pad()'' (PHP 8.3). It has no padding function for grapheme clusters, the unit the ''grapheme_*'' functions of ext/intl use for "a character as a user sees it". This RFC proposes ''grapheme_str_pad()'', as already suggested in the Future Scope of the [[rfc:mb_str_pad|mb_str_pad RFC]]. The same visible text should get the same padding: ===== Proposal ===== Add the following function to ext/intl: It pads ''$string'' on the left, the right or both sides with ''$pad_string'' until the result is ''$length'' grapheme clusters long. ''$length'' and the length of the input are counted in grapheme clusters, as ''grapheme_strlen()'' counts them. The function mirrors ''mb_str_pad()'' and ''str_pad()'': * If ''$length'' is negative, or less than or equal to the length of ''$string'', ''$string'' is returned unchanged. * ''$pad_type'' is one of the existing constants ''STR_PAD_LEFT'', ''STR_PAD_RIGHT'' (default) or ''STR_PAD_BOTH''. With ''STR_PAD_BOTH'' the extra grapheme cluster, if any, goes to the right, like in ''str_pad()''. * ''$pad_string'' is repeated as often as needed. If the last copy does not fit entirely, it is cut **on a grapheme cluster boundary**. The padding string is never split inside a grapheme cluster. * For ASCII input the result is identical to ''str_pad()''. The two-byte sequence ''"\r\n"'' is a single grapheme cluster, as in all ''grapheme_*'' functions. ==== Why not mb_str_pad() ==== ''mb_str_pad()'' counts code points. Many characters a user perceives as one are made of several code points: letters with combining marks (text in Unicode normalization form NFD, which some platforms and input methods produce), Japanese kana with a combining dakuten (が = か + U+3099), most Indic scripts, emoji with skin tone modifiers and emoji ZWJ sequences. For such text ''mb_str_pad()'' adds too little padding, and it can split the padding string inside a grapheme cluster, which changes the padding text itself: The ''grapheme_*'' functions exist precisely for this unit. Adding the padding function completes the set of byte, code point and grapheme cluster variants, as ''grapheme_str_split()'' (PHP 8.4) and ''grapheme_strrev()'' (PHP 8.6) did for ''str_split()'' and ''strrev()''. ==== Doing it in userland ==== A correct userland version needs ''grapheme_strlen()'' for the input, ''grapheme_strlen()'' and ''grapheme_substr()'' for the padding string, and the same left/right arithmetic as ''str_pad()''. Symfony's String component does exactly this in ''UnicodeString::padStart()'', ''padEnd()'' and ''padBoth()'', whose length is ''grapheme_strlen()''. Everybody else has to reimplement it, or use ''mb_str_pad()'' and get the results shown above. ==== Error conditions ==== Same as ''mb_str_pad()'': * An empty ''$pad_string'' throws a ''ValueError'', unless no padding is needed. * A ''$pad_type'' other than ''STR_PAD_LEFT'', ''STR_PAD_RIGHT'' or ''STR_PAD_BOTH'' throws a ''ValueError''. Like ''grapheme_strlen()'', invalid UTF-8 in ''$string'' or ''$pad_string'' makes the function return ''false'' and sets the intl error (''intl_get_error_code()'' / ''intl_get_error_message()''). ==== Examples ==== ===== Backward Incompatible Changes ===== A userland function named ''grapheme_str_pad()'' in the global namespace would conflict. No definitions were found on 2026-11-03 with GitHub code search (''"function grapheme_str_pad("'', PHP) or Sourcegraph (''grapheme_str_pad'', PHP). No other changes. ===== Proposed PHP Version(s) ===== Next PHP 8.x (PHP 8.7). ===== RFC Impact ===== ==== To the Ecosystem ==== None beyond knowing the new function. ==== To Existing Extensions ==== Adds ''grapheme_str_pad()'' to ext/intl. No change to existing functions. ==== To SAPIs ==== None. ===== Open Issues ===== None. ===== Future Scope ===== * Padding to a display width (where East Asian wide characters and many emoji take two terminal columns, see ''mb_strwidth()'') is a different problem and is not addressed by this RFC. ''grapheme_str_pad()'' counts grapheme clusters, consistently with the other ''grapheme_*'' functions. ===== Voting Choices ===== Primary Vote requiring a 2/3 majority to accept the RFC: * Yes * No * Abstain ===== Patches and Tests ===== Implementation with tests: https://github.com/php/php-src/pull/25179 ===== Implementation ===== After the RFC is implemented, this section will contain: - the version(s) it was merged into - a link to the git commit(s) - a link to the PHP manual entry for the feature ===== References ===== * [[rfc:mb_str_pad|mb_str_pad RFC]], Future Scope: "In the future we could add a string padding function that works on grapheme clusters instead of code points: grapheme_str_pad(). This should be added to ext/intl. This will of course require another RFC." * [[https://github.com/php/php-src/issues/10203|GH-10203]], where a grapheme cluster variant of mb_str_pad() was first suggested. * [[rfc:grapheme_str_split|grapheme_str_split RFC]] and [[rfc:grapheme_strrev|grapheme_strrev RFC]], previous grapheme counterparts of string functions. * Discussion thread: https://news-web.php.net/php.internals/132995 ===== Rejected Features ===== None yet. ===== Changelog ===== * 0.1 (2026-11-03): Initial draft.