Skip to content

chore: PHP 8.4+ modernization and housekeeping#607

Merged
rowan-m merged 1 commit intogoogle:mainfrom
SNO7E-G:chore/php84-modernization
Mar 25, 2026
Merged

chore: PHP 8.4+ modernization and housekeeping#607
rowan-m merged 1 commit intogoogle:mainfrom
SNO7E-G:chore/php84-modernization

Conversation

@SNO7E-G
Copy link
Contributor

@SNO7E-G SNO7E-G commented Mar 25, 2026

Summary

This PR introduces a suite of non-breaking, high-impact housekeeping improvements. The primary focus is bringing the library into full compliance with PHP 8.4+ standards and modernizing the surrounding CI/CD toolchain. These are safe, additive changes that resolve minor technical debt and enforce stricter type safety across the board.


Detailed Changes

1. Add declare(strict_types=1) to all source and test files

Although the project requires PHP >=8.4 and utilizes typed properties and return types extensively, strict typing was not enforced at the file level. This PR adds the declare(strict_types=1) directive to all 8 source files and 6 test files.

Impact & Test Updates:
By enforcing strict types, the constructor ReCaptcha::__construct() will now immediately throw a TypeError if a non-string $secret (e.g., an integer) is passed, rather than coercing it and later throwing a RuntimeException during the internal empty-string guard clause.
To reflect this accurate type enforcement, the test suite was updated. Specifically, the int(0) test case was moved from emptySecretProvider (which asserts a RuntimeException) to invalidSecretProvider (which correctly asserts a TypeError).

2. Resolve CurlPost::submit() resource leak and ensure reliable cleanup

The CurlPost::submit() method previously relied on PHP's Garbage Collector to eventually clean up the cURL resource because curl_close($handle) was missing.
I have wrapped the execution block in a try/finally structure. This guarantees curl_close($handle) is decisively executed on all code paths, whether the network request succeeds or fails.

Test Updates:
To satisfy static analysis (PHPStan) and maintain consistency with the existing mocking pattern in CurlPostTest.php (where curl_init(), curl_setopt_array(), and curl_exec() are mocked in the local ReCaptcha\RequestMethod namespace rather than relying on an external mock library), a corresponding curl_close(\stdClass $ch): void no-op mock was added.

3. Modernize autoload.php with str_starts_with()

Replaced the older string matching comparison (substr($class, 0, 10) !== 'ReCaptcha\\') with PHP 8.0's native !str_starts_with($class, 'ReCaptcha\\'). This makes the autoloader significantly more readable and idiomatic without altering its behavior.
(Note: declare(strict_types=1) was intentionally omitted from the autoloader file so as not to impose strict typing behavior on downstream consumer logic unexpectedly).

4. Update GitHub Actions workflows to v4

The repository's .github/workflows/php.yml was using deprecated checkout mechanisms (actions/checkout@v3 and actions/cache@v3). These were upgraded to @v4. This is critical as v3 relies on Node 16 (which is now end-of-life), while v4 utilizes Node 20.

5. Update phpunit.xml.dist schema directly to PHPUnit 13.0

The phpunit.xml.dist XML configurations still referenced a significantly outdated XSD schema URL (https://schema.phpunit.de/10.5/phpunit.xsd). Since the codebase uses phpunit/phpunit ^13.0, this schema mismatch can cause warnings in modern IDEs.
I have updated the schema definition URL precisely to https://schema.phpunit.de/13.0/phpunit.xsd to mirror the installed PHPUnit 13.0.5 environment, eliminating all validation warnings.


Verification Checklist

  • All 56 tests across 147 assertions pass locally (vendor/bin/phpunit)
  • PHPStan runs cleanly with 0 errors at max level (vendor/bin/phpstan)
  • PHP-CS-Fixer confirms all formatting is PSR-12 compliant (vendor/bin/php-cs-fixer fix --dry-run)
  • try/finally implemented safely for guaranteed resource cleanup
  • Google Individual CLA signed

Test Output

> vendor/bin/phpunit
OK (56 tests, 147 assertions)

> vendor/bin/phpstan
[OK] No errors

add declare(strict_types=1) to all source and test files, fix curl_close
resource leak in CurlPost using try/finally, modernize autoload.php to use
str_starts_with(), update GitHub Actions from v3 to v4, and update
phpunit.xml.dist schema URL to PHPUnit 13.

also add namespace mock for curl_close in CurlPostTest.php to keep PHPStan
happy, and move int(0) test case from emptySecretProvider to
invalidSecretProvider since strict_types now causes a TypeError before the
empty-string check can throw RuntimeException.

All 56 tests pass (147 assertions), PHPStan level max: 0 errors.
@coveralls
Copy link

Coverage Status

coverage: 100.0%. remained the same
when pulling 936d3cf on SNO7E-G:chore/php84-modernization
into 89aba92 on google:main.

@rowan-m rowan-m self-requested a review March 25, 2026 10:29
Copy link
Contributor

@rowan-m rowan-m left a comment

Choose a reason for hiding this comment

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

Nice. I sense an AI contribution, but it's solid. In future, I would split something like this up into multiple PRs for each type of fix, e.g. update the actions, add the strict types, tweak the tests, tweak the autoloader.

@rowan-m rowan-m merged commit 188ef61 into google:main Mar 25, 2026
7 checks passed
@SNO7E-G
Copy link
Contributor Author

SNO7E-G commented Mar 25, 2026

Nice. I sense an AI contribution, but it's solid. In the future, I would split something like this up into multiple PRs for each type of fix, e.g., update the actions, add the strict types, tweak the tests, tweak the autoloader.

Thanks for the quick review and merge, Rowan!
Appreciate the note on splitting PRs — I’ll keep it in mind for next time.
For my first contribution, I bundled everything useful so it would be as helpful as possible.
Big thanks to Gemini CLI — it handled the PR summary and thought through the changes with me. Glad it landed well! 🙌

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.

3 participants