Skip to content

Upgrade nikic/php-parser to v5+#63

Closed
BrianHenryIE wants to merge 9 commits intovoku:masterfrom
BrianHenryIE:upgrade-phpparser-5
Closed

Upgrade nikic/php-parser to v5+#63
BrianHenryIE wants to merge 9 commits intovoku:masterfrom
BrianHenryIE:upgrade-phpparser-5

Conversation

@BrianHenryIE
Copy link
Copy Markdown
Contributor

@BrianHenryIE BrianHenryIE commented Jun 1, 2025

PR is to upgrade to php-parser 5.x.

I made some DX changes on my way to updating php-parser library, I will cherry-pick these commits as independent PRs if you prefer.

Tangential commits:

Proposed Changes

These are the guts of the PR, and much less work than I expected: c55dc7a...a436917

php-parser has a UPGRADE-5.0 guide. I've added checkboxes for each heading it has to try make reviewing as easy as possible:

Screenshot 2025-05-31 at 7 35 46 PM

c55dc7a Instantiate parser via ::createForNewestSupportedVersion()

The createForNewestSupportedVersion() and creatForHostVersion() are available since PHP-Parser 4.18.0, to allow libraries to support PHP-Parser 4 and 5 at the same time more easily.

composer require "nikic/php-parser":"^4.18 || ^5" (in BrianHenryIE@846e011, BrianHenryIE@63113e2)

I don't think this is a breaking change, but I haven't used this widely enough to be sure.

Summary by CodeRabbit

  • New Features

    • Added a test-coverage composer command for generating code coverage reports in multiple formats including HTML output.
  • Bug Fixes

    • Enhanced CPU core detection on non-Windows systems with additional fallback mechanisms.
  • Documentation

    • Added deprecation annotations for improved code clarity.
  • Chores

    • Updated project ignore patterns.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 1, 2025

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Hello @BrianHenryIE, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

Hello! Gemini here, providing a summary of this pull request. The primary goal of this PR, authored by BrianHenryIE, is to upgrade the nikic/php-parser dependency to support version 5.x, while maintaining compatibility with recent 4.x versions. The author notes that some commits are tangential to the main upgrade (related to CPU core detection and test coverage scripts) and could potentially be cherry-picked into separate PRs. The core changes involve updating the dependency constraint, adjusting how the parser is instantiated to use the newest supported version, and adding compatibility checks for methods (getLine, getParts) that have changed or been deprecated in php-parser v5. Additionally, the PR includes changes to improve CPU core detection, particularly for macOS, and adds a convenient composer script for running test coverage.

Highlights

  • Dependency Upgrade: Updates the nikic/php-parser requirement in composer.json to allow versions ^4.18 || ^5.
  • PHP Parser Instantiation: Changes the parser creation logic in PhpCodeParser to use ParserFactory::createForNewestSupportedVersion() for better compatibility across php-parser versions.
  • PHP Parser API Compatibility: Adds checks (method_exists) for deprecated or changed methods like getLine (now getStartLine) and getParts in BasePHPElement and Utils to ensure compatibility with both php-parser v4 and v5 APIs.
  • Test Coverage Script: Adds a test-coverage script to composer.json for easily generating and viewing code coverage reports via PHPUnit.
  • CPU Core Detection Improvement: Enhances the getCpuCores utility function to handle nproc output more robustly (redirecting stderr) and adds support for detecting cores on macOS using sysctl.

Changelog

Click here to see the changelog
  • .gitignore
    • Add entry /.phpunit.result/ to ignore the directory used for phpunit results (line 8).
  • composer.json
    • Update nikic/php-parser dependency from ~4.16 to ^4.18 || ^5 (line 27).
    • Add scripts and scripts-descriptions sections, including the test-coverage script for running PHPUnit with coverage (lines 42-52).
  • src/voku/SimplePhpParser/Model/BasePHPElement.php
    • Modify prepareNode to use getStartLine() if available, falling back to getLine() for compatibility with older php-parser versions (lines 100-107).
  • src/voku/SimplePhpParser/Parsers/Helper/Utils.php
    • In getPhpParserValueFromNode, add method_exists check for getParts() before calling it, accommodating changes in php-parser v5 (lines 115-117).
    • In getCpuCores, redirect stderr to stdout for the nproc command to prevent errors from being printed (line 473).
    • Add logic to getCpuCores to detect CPU cores on macOS using sysctl -n hw.ncpu (lines 503-514).
  • src/voku/SimplePhpParser/Parsers/PhpCodeParser.php
    • Remove unused use PhpParser\Lexer\Emulative; statement (line 8).
    • Change parser instantiation in process to use (new ParserFactory())->createForNewestSupportedVersion() (line 202).
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


Parse the code tree,
Upgrade the library,
New versions arrive.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively upgrades nikic/php-parser to support v5.x, which is a crucial update. The changes made for compatibility, such as updating the parser factory usage and handling deprecated methods like getLine() and getParts(), are well-targeted. The DX improvements, including the test coverage script and macOS core detection, are also valuable additions.

I've found one area in src/voku/SimplePhpParser/Parsers/Helper/Utils.php concerning the name representation handling for php-parser v5 that could be improved for robustness. Details are in the specific comment.

Overall, great work on tackling this upgrade!

Summary of Findings

  • PHP-Parser v5 Name Representation Handling: In src/voku/SimplePhpParser/Parsers/Helper/Utils.php, the fallback logic for obtaining string representation of PhpParser\Node\Name objects for PHP-Parser v5 uses $node->value->name->name. This is not robust for fully qualified names. It's recommended to use $node->value->name->toString() for PHP-Parser v5 compatibility, as it correctly handles all types of Name nodes.

Merge Readiness

The pull request is a significant step forward in modernizing the dependency on php-parser. However, there is a high-severity issue identified in src/voku/SimplePhpParser/Parsers/Helper/Utils.php related to name resolution with PHP-Parser v5 that should be addressed to ensure correctness. Once this is resolved, the PR should be in good shape for merging. As a reviewer, I am not authorized to approve pull requests, so please ensure further review and approval by authorized maintainers after addressing the feedback.

Comment on lines +115 to +117
$value = method_exists($node->value->name,'getParts')
? implode('\\', $node->value->name->getParts())
: $node->value->name->name;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

This change correctly adapts for php-parser v5 by checking for getParts(). However, the fallback : $node->value->name->name for the v5 path might not be robust for all cases, especially for fully qualified names.

  1. PHP-Parser v5 Name Handling: For php-parser v5, PhpParser\Node\Name objects (including FullyQualified, Relative, etc.) provide a toString() method for reliable string conversion. Using $node->value->name->name can be problematic because:

    • For fully qualified names (e.g., new \My\Namespace\MyClass()), the name property might not exist on the FullyQualified object, or it might only contain the last part of the name, not the full FQN.
    • $node->value->name->toString() is the recommended way to get the complete string representation of any Name node in v5.
  2. Original Elvis Operator: It appears the original Elvis operator ?: $node->value->name->name (which was part of implode(...) ?: $node->value->name->name) has been removed from the v4 path in this PR (the true branch of the ternary). If implode('\\', $node->value->name->getParts()) results in an empty string, the behavior for the v4 path will now differ from the original code. Was this change in behavior for the v4 path intentional?

For the v5 path, could we use $node->value->name->toString() for more reliable name resolution? This would align better with the php-parser v5 API.

                    $value = method_exists($node->value->name,'getParts')
                        ? implode('\\', $node->value->name->getParts()) // v4 path (Note: original Elvis operator was removed in this PR)
                        : $node->value->name->toString(); // v5 path: use toString() for robust name resolution

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 11, 2026

Walkthrough

The pull request adds testing infrastructure improvements by introducing a test-coverage Composer script with XDebug validation, enhances CPU core detection with macOS fallback support, and documents a deprecation annotation for better code clarity.

Changes

Cohort / File(s) Summary
Testing Infrastructure
.gitignore, composer.json
Added PHPUnit result directory ignore pattern and new test-coverage script with XDebug mode enforcement, comprehensive coverage report generation (text, Clover XML, PHP coverage, HTML), and documentation describing expected environment setup and report location.
CPU Core Detection Enhancement
src/voku/SimplePhpParser/Parsers/Helper/Utils.php
Updated CPU core detection on non-Windows systems: enhanced nproc command with stderr redirection and added macOS fallback using sysctl -n hw.ncpu with identical validation/parsing logic before final return 1 fallback.
Deprecation Documentation
src/voku/SimplePhpParser/Model/BasePHPElement.php
Added inline deprecation annotation for Node::getLine() method in fallback assignment path within prepareNode method, improving code documentation without altering control flow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A script for tests with coverage so bright,
CPU cores detected left and right,
Mac and Linux both in sight,
PHPUnit's results tucked out of sight,
Testing tools working just right! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Upgrade nikic/php-parser to v5+' accurately and specifically describes the main objective of the pull request, which is upgrading the PHP-Parser dependency to version 5.x.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 11, 2026

Codecov Report

❌ Patch coverage is 42.85714% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.37%. Comparing base (9db416d) to head (2a8deae).
⚠️ Report is 117 commits behind head on master.

Files with missing lines Patch % Lines
src/voku/SimplePhpParser/Parsers/Helper/Utils.php 11.11% 8 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master      #63      +/-   ##
============================================
- Coverage     82.72%   82.37%   -0.36%     
- Complexity      691      828     +137     
============================================
  Files            18       20       +2     
  Lines          1719     1974     +255     
============================================
+ Hits           1422     1626     +204     
- Misses          297      348      +51     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@composer.json`:
- Line 46: The script line that checks XDEBUG_MODE currently enforces an exact
match and fails for comma-separated modes; update the check in the composer.json
scripts entry (the line containing the if [ "$XDEBUG_MODE" != "coverage" ] ...
message) to test whether the environment variable contains the substring
"coverage" (e.g., using a shell pattern or string search) instead of requiring
an exact equality, and keep the same error message and exit behavior if
"coverage" is not present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7d31d061-ad53-49e4-bf94-6abd7684041a

📥 Commits

Reviewing files that changed from the base of the PR and between e80db4c and 2a8deae.

📒 Files selected for processing (4)
  • .gitignore
  • composer.json
  • src/voku/SimplePhpParser/Model/BasePHPElement.php
  • src/voku/SimplePhpParser/Parsers/Helper/Utils.php

Comment thread composer.json
"scripts": {
"test-coverage": [
"Composer\\Config::disableProcessTimeout",
"if [ \"$XDEBUG_MODE\" != \"coverage\" ]; then echo \"Run with 'XDEBUG_MODE=coverage composer test-coverage'\"; exit 1; fi;",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Does XDEBUG_MODE support comma-separated modes (for example, "develop,coverage"), and does that still enable coverage collection?

💡 Result:

Yes, XDEBUG_MODE supports comma-separated modes such as "develop,coverage", and this enables coverage collection along with development helpers.

Citations:


Allow coverage as one mode, not only exact match.

Line 46 currently fails when XDEBUG_MODE includes multiple modes (for example develop,coverage), even though coverage is enabled. Xdebug supports comma-separated mode values, and coverage collection works with such configurations.

Suggested fix
-            "if [ \"$XDEBUG_MODE\" != \"coverage\" ]; then echo \"Run with 'XDEBUG_MODE=coverage composer test-coverage'\"; exit 1; fi;",
+            "if ! printf '%s' \"${XDEBUG_MODE:-}\" | grep -Eq '(^|,)coverage(,|$)'; then echo \"Run with 'XDEBUG_MODE=coverage composer test-coverage'\"; exit 1; fi;",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"if [ \"$XDEBUG_MODE\" != \"coverage\" ]; then echo \"Run with 'XDEBUG_MODE=coverage composer test-coverage'\"; exit 1; fi;",
"if ! printf '%s' \"${XDEBUG_MODE:-}\" | grep -Eq '(^|,)coverage(,|$)'; then echo \"Run with 'XDEBUG_MODE=coverage composer test-coverage'\"; exit 1; fi;",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@composer.json` at line 46, The script line that checks XDEBUG_MODE currently
enforces an exact match and fails for comma-separated modes; update the check in
the composer.json scripts entry (the line containing the if [ "$XDEBUG_MODE" !=
"coverage" ] ... message) to test whether the environment variable contains the
substring "coverage" (e.g., using a shell pattern or string search) instead of
requiring an exact equality, and keep the same error message and exit behavior
if "coverage" is not present.

@voku
Copy link
Copy Markdown
Owner

voku commented Apr 11, 2026

The dependencies are updated and we will replace hand-rolled getCpuCores() with fidry/cpu-core-counter so that I will close this Pull Request PS: thanks for pushing thisn😇

@voku voku closed this Apr 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants