Skip to content

[PHP 8.6] Internal functions with #[\Deprecated]: native-fallback parity coverage - #231

Merged
lisachenko merged 2 commits into
masterfrom
claude/php86-215-internal-deprecated
Aug 25, 2026
Merged

[PHP 8.6] Internal functions with #[\Deprecated]: native-fallback parity coverage#231
lisachenko merged 2 commits into
masterfrom
claude/php86-215-internal-deprecated

Conversation

@lisachenko

@lisachenko lisachenko commented Aug 25, 2026

Copy link
Copy Markdown
Member

Refs #215

Outcome: confirmed, no production code change needed

Verified on a local PHP 8.6.0beta1 build that strcoll() and the other internal functions newly annotated in 8.6 are reflected correctly, and that no gap exists in this library.

Findings

The fallback is structural, not conditional. Go\ParserReflection\ReflectionFunction is constructed exclusively from a PhpParser\Node\Stmt\Function_ AST node (ReflectionFileNamespace::findFunctions() is the only construction site in src/). Internal functions have no source file (getFileName() is false), so they can never enter the parsing path — a consumer asking for strcoll() necessarily gets a plain \ReflectionFunction. Since the parsed class extends the native one, code type-hinting \ReflectionFunction accepts both transparently. Consistently, ReflectionFunctionLikeTrait::isInternal() hard-returns false and isUserDefined() hard-returns true.

Native reflection reports everything as expected on 8.6. Probed directly on the 8.6 binary:

  • (new \ReflectionFunction('strcoll'))->isDeprecated()true (it is false on 8.5)
  • getAttributes(\Deprecated::class) → one attribute, getName() is Deprecated, arguments ['message' => 'use Collator::compare() instead', 'since' => '8.6'], and newInstance() yields a real \Deprecated instance
  • __toString()Function [ <internal, deprecated:standard> function strcoll ] { ... }

For scale: 37 internal functions carry #[\Deprecated] on 8.5 versus 55 on 8.6, so the downstream goaop/framework proxy-generator diff is the expected consequence of the engine change rather than a reflection defect here.

No deprecation notices are emitted by reflecting these functionsisDeprecated(), getAttributes() and __toString() are all side-effect free, so the added tests are safe under strict error reporting.

Coverage added

Four test methods in tests/DeprecatedAndFunctionLikeGapsTest.php, alongside the existing PHP 8.4 #[\Deprecated] coverage (tests only, no src/ changes):

  • testInternalFunctionsAreReflectedByTheNativeFallback() — runtime-agnostic: internal functions have no file name and are never resolved to a parsed reflection, while a parsed function stays user-defined and remains a drop-in \ReflectionFunction.
  • testDeprecatedInternalFunctionIsReflectedOnEveryRuntime() — runtime-agnostic: utf8_encode() (deprecated since 8.2) reports its attribute payload and its deprecated marker in __toString(), with strlen() as a negative control. This proves the mechanism is not specific to 8.6.
  • testInternalFunctionDeprecatedInPhp86IsReflectedWithItsAttributePayload() — guarded by PHP_VERSION_ID >= 80600: strcoll() reports deprecated with since: '8.6' and message: 'use Collator::compare() instead'.
  • testInternalFunctionDeprecatedInPhp86IsNotDeprecatedBefore() — guarded by PHP_VERSION_ID < 80600: strcoll() reports no deprecation and no attribute, pinning the transition from the other side.

Each version-specific test is skipped (not failed) on the runtime it does not target, so the suite stays green on both.

Unrelated observation (not addressed here)

While probing, one pre-existing difference surfaced in the parsed attribute layer, unrelated to internal functions and to this issue: for a user-land #[\Deprecated(message: '...', since: '4.0')], native ReflectionAttribute::getArguments() returns the named arguments keyed by name, whereas Go\ParserReflection\ReflectionAttribute::getArguments() returns them positionally. It affects every attribute with named arguments, not just \Deprecated. Left untouched to keep this verification ticket minimal — worth its own issue if wanted.

Local validation

Check Result
vendor/bin/phpunit (PHP 8.5.9) OK — 13747 tests, 15423 assertions, 134 skipped, 2 incomplete
php8.6 vendor/bin/phpunit (PHP 8.6.0beta1) OK — 13747 tests, 15429 assertions, 134 skipped, 3 incomplete
vendor/bin/phpstan analyse src --no-progress (level 10) [OK] No errors

Baseline on master (PHP 8.5) was 13743 tests / 133 skipped; the four new tests account for the difference, one of which is always skipped on a given runtime by design.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Sy8BcM8ivUEpu8uVm7wADn

claude added 2 commits August 25, 2026 10:03
…ctions

PHP 8.6 attaches #[\Deprecated] to a number of previously-undeprecated internal
functions, strcoll() among them. Internal functions have no source file, so the
AST parser can never reflect them and the native reflection is always used
instead, which reports the attribute correctly without any change in this
library.

Pins that behaviour with parity tests next to the existing #[\Deprecated]
coverage:

- internal functions are never resolved to a parsed reflection, while parsed
  functions are always user-defined and remain drop-in \ReflectionFunction
  replacements;
- utf8_encode(), deprecated since PHP 8.2, proves the mechanism is not specific
  to PHP 8.6, with strlen() as a negative control;
- strcoll() reports the expected #[\Deprecated] payload on PHP 8.6 and reports
  no deprecation before it, pinning the transition from both sides.

Refs #215

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sy8BcM8ivUEpu8uVm7wADn
@lisachenko
lisachenko marked this pull request as ready for review August 25, 2026 14:08
@lisachenko
lisachenko merged commit 42d833e into master Aug 25, 2026
7 checks passed
@lisachenko
lisachenko deleted the claude/php86-215-internal-deprecated branch August 25, 2026 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants