Support symfony/options-resolver 8 (fixes #290)#291
Merged
Conversation
Nested-options-via-Closure passed to setDefaults() was deprecated in options-resolver 7.3 and removed in 8.0, leaving the closures stored as raw defaults and causing "Cannot use object of type Closure as array" in Client::postResolve(). Bind each nested resolver explicitly via setOptions() when available, falling back to the legacy closure-default pattern on older versions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PHPStan resolves OptionsResolver against the installed version (>= 7.3 in CI), where setOptions() exists, so the runtime method_exists() guard appears tautological. Ignore the function.alreadyNarrowedType identifier on that line so the guard remains in place for older OptionsResolver versions allowed by the composer constraint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A recent php-http/cache-plugin release moved handleRequest() from CachePlugin to the new @internal AbstractCachePlugin parent. Update the existing argument.type ignore to the new class name and add a baseline entry for the resulting method.internalClass error on the same call site, so CI unblocks. Long-term fix is to stop calling the internal parent method, tracked separately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The method_exists() guard evaluates to true on PHP >= 8.2 (installs options-resolver 7.3+ where setOptions exists) and false on PHP < 8.2 (installs 4.4-7.2 where it doesn't). PHPStan reports different identifiers per outcome (function.alreadyNarrowedType vs function.impossibleType). List both in the inline ignore so the relevant one matches on each PHP version in the CI matrix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PHPStan analyzes against the single installed OptionsResolver version on each CI job, so the method_exists() guard appears tautological as either "always true" (>= 7.3 on PHP 8.2+) or "always false" (< 7.3 on PHP 7.4- 8.1) with different identifiers per outcome. Inline @phpstan-ignore treats every listed identifier as required, so the non-firing one trips reportUnmatchedIgnoredErrors. Use the baseline form with reportUnmatched: false on both entries, so whichever fires gets silenced and the other entry quietly does nothing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
neildaniels
added a commit
that referenced
this pull request
May 19, 2026
Allow the dev-side Symfony components to install on v8, matching the constraint widened for symfony/options-resolver in #291. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Fixes #290. The library crashed on
symfony/options-resolver8 withCannot use object of type Closure as array in Client.php:216because v8.0 removed support for defining nested options by passing aClosuretosetDefaults()(deprecated in 7.3, removed in 8.0). The closures stayed as raw default values and$options['hydration']arrived inpostResolve()as aClosure.Changes
Options-resolver fix (
composer.json,lib/Tmdb/Client.php):symfony/options-resolverconstraint to^4.4 || ^5 || ^6 || ^7 || ^8.http,hydration,event_dispatcher) viaOptionsResolver::setOptions()when available (introduced in 7.3), falling back to the legacy closure-as-default pattern on older versions. The originalsetDefaults([...])block is preserved almost verbatim — each nested closure is captured into a local via'key' => $var = function (...)and then re-bound afterwards.PHPStan baseline updates (
phpstan-baseline.neon):method_exists($resolver, 'setOptions')guard is tautological from PHPStan's perspective on a given CI job (always-true when the installed OptionsResolver has the method, always-false otherwise), with different identifiers per outcome. Both outcomes are baselined withreportUnmatched: falseso whichever fires per job gets silenced and the other entry sits idle without tripping the unmatched-ignore check.php-http/cache-pluginrelease between Update composer dependencies #289's last-green CI on4.1(2026-01-30) and now movedhandleRequest()to the new@internal AbstractCachePluginparent, invalidating the existingargument.typeignore onPsr6CachedRequestListener.php:106and adding a newmethod.internalClasserror. The repo has nocomposer.lock, so every CI run pulls the latest cache-plugin —4.1would also fail PHPStan on a fresh re-run today. Baseline refreshed accordingly. Long-term fix is to stop calling the internal parent method, tracked separately.Why a runtime branch instead of bumping the floor
setOptions()only exists from options-resolver 7.3, which requires PHP ≥ 8.2. Bumping the constraint to^7.3 || ^8would implicitly force the library to PHP 8.2+, breaking installs on the lib's currently-declared"php": "^7.3 || ^8.0"floor. Themethod_exists()guard preserves that floor at the cost of the two-entry baseline silencing.Coverage
The CI matrix in
.github/workflows/continuous-integration.ymlruns PHP 7.4–8.5 × {normal, low, dev}. With the constraint widened to^8, jobs on PHP ≥ 8.4 +normal/devwill now install options-resolver 8 and exercise thesetOptions()path — the previous matrix passed only because the old constraint excluded v8 entirely, which is how #290 escaped detection.lowjobs pin v4.4 and exercise the legacy fallback. All 59 PR checks green.Reviewer notes
symfony/options-resolveris already inrequire(composer.json:36), and the PHP 8.4 implicit-nullable deprecation inHttpClient::getOptionswas fixed in 5a9ea4c.Test plan
Tmdb\Clienton PHP 8.4 withsymfony/options-resolver:^8installedTmdb\Clienton PHP 7.4 withsymfony/options-resolver:4.4installed (legacy path)🤖 Generated with Claude Code