Conversation
This was referenced Aug 14, 2026
`Hook_Reflector::getName()` short-circuited on `Scalar\String_` nodes and returned the interpreted string value. Escape sequences were therefore resolved, so `do_action( "\x09tab" )` exported a literal tab and `do_action( "\xC0 bad" )` exported a raw 0xC0 byte. That byte is not valid UTF-8, `json_encode()` returns `false` for it, and `wp parser export` silently produced no JSON at all for the whole run. Route string nodes through `Pretty_Printer` like every other expression. The printer returns php-parser's `rawValue` attribute, which is the source-verbatim spelling, and `cleanupName()` strips the quotes. Also check `json_encode()` for failure in `Command::_get_phpdoc_data()` and fail loudly with `json_last_error_msg()` instead of writing an empty file.
The pretty printer inherits an override that returns PHP-Parser's `rawValue` attribute so escape sequences are not interpreted. PHP-Parser sets that attribute to the body of a doc string, without the delimiters, so `apply_filters( 'f', <<<EOT ... EOT, 2 )` exported its argument as a bare `body` string with embedded newlines instead of PHP source. Print heredoc and nowdoc nodes with the default printer, which reproduces the `<<<LABEL ... LABEL` form and does not interpret escape sequences in doc strings either.
`pName_FullyQualified()` prints single-segment fully-qualified names without the leading backslash regardless of namespace context, so inside a namespaced file the printed form denotes a namespaced symbol rather than the global one. This is an accepted limitation because the parser targets global-namespace WordPress core code.
The global namespace prefixes are stripped from inline `{@link}` and
`{@see}` references after the DocBlock text has been rendered, so the
stripping also reached into rendered code regions and silently deleted
the backslash an author had written in a verbatim code sample.
Carve out `<code>` regions before stripping, the same way `fix_newlines()`
protects the newlines in those regions, so code samples are exported as
they were written.
The quote-stripping pattern required a body free of quote characters, so a hook name that contained one, like `do_action( "it's" );`, was exported with the quotes that surround it in the source. Match the opening quote and require the same quote at the end, allowing the body to hold the other quote character or an escaped copy of the delimiter. Only that pair is stripped; the body keeps its source spelling, so `do_action( 'it\'s' );` exports as `it\'s`. Concatenated expressions still fall through to the dynamic-name handling below.
`Method_Call_Reflector::_getClassMapping()` maps a handful of WordPress factory functions to the class they return, so that `get_current_screen()->add_help_tab()` is exported as a use of `WP_Screen::add_help_tab()`. The lookup never matched before this branch, because the printed receiver carried a leading backslash that the mapping keys do not have. Pin the restored behavior with a test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #254.
What changed
Why
The PHP-Parser 5 compatibility cleanup treated documentation and hook literals as identifiers. It removed meaningful backslashes. Simply deleting that cleanup also caused broad JSON churn such as
falsebecoming\false.Keep syntax normalization where it belongs. Leave text alone.
Testing
npm run test:phpunit— 28 tests, 158 assertions; 11 pre-existing PHPUnit deprecation warnings.php tests/prep-diff-test.phpwp-includesexport: expected documentation escapes remain; no stray global prefixes in defaults, constant values, references, or call-class metadata.