Skip to content

Fix result cache invalidation with @var referenced classes - #6343

Merged
ondrejmirtes merged 2 commits into
phpstan:2.2.xfrom
mika-si:fix-cache
Sep 3, 2026
Merged

ondrejmirtes merged 2 commits into
phpstan:2.2.xfrom
mika-si:fix-cache

Conversation

@mika-si

@mika-si mika-si commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

My project started encountering stale result cache entries after updating to lvl7. Found that the result cache does not register a file dependency for a class that is only referenced by @var PHPDoc, like how phtml template files commonly do.

Not sure if there's more elegant way to do this?

@staabm staabm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I verfied the e2e test - and it looks good. the fix looks sound.

I am worried that this fix might incur a perf hit since every Stmt needs to be inspected for comments. lets see what others think about it

@ondrejmirtes

Copy link
Copy Markdown
Member

Thanks! I was worried about the performance hit, so I instrumented the FileTypeMapper::getResolvedPhpDoc() cache while analysing phpstan-src src/ in a single process.

Good news: for Expression, Return_, Foreach_, If_ etc. your call hits the same cache entry that processStmtVarAnnotation() / getOverridingThrowPoints() already populated (same file/class/trait/function/text key). 100 % hits, CPU delta within noise (+0.3 %, 4 ABBA pairs).

Two redundancies though:

  • Stmt\Property is already covered by the ClassPropertyNode branch below.
  • InClassMethodNode, InClassNode, InFunctionNode and InTraitNode extend Node\Stmt and copy the original comments, so every method/class docblock is scanned twice.

Please restrict the new branch to the statements NodeScopeResolver::processStmtNode() feeds into processStmtVarAnnotation():

if (
	$node instanceof Node\Stmt
	&& !$node instanceof VirtualNode
	&& !$node instanceof Node\Stmt\ClassLike
	&& !$node instanceof Node\Stmt\ClassMethod
	&& !$node instanceof Node\Stmt\Function_
	&& !$node instanceof Node\Stmt\Property
	&& !$node instanceof Node\Stmt\ClassConst
	&& !$node instanceof Node\Stmt\Const_
) {
	$this->extractStmtVarTags($node, $scope, $dependenciesReflections);
}

I verified this variant: 251 calls, all cache hits, miss count identical to the branch without the PR, and your e2e test still passes (and fails without the fix).

Also please remove the str_contains('var') pre-filter. It's a bad heuristic (matches $var, "variable", "covariant"…) and with the restriction above the cache makes it unnecessary.

@ondrejmirtes

ondrejmirtes commented Sep 3, 2026

Copy link
Copy Markdown
Member

I like it, just run make cs-fix locally and forcepush. The other failures are moot (happening on other PRs too).

@ondrejmirtes

Copy link
Copy Markdown
Member

I'm sorry, there's now a conflict. I was fixing some result cache misses too.

@ondrejmirtes

Copy link
Copy Markdown
Member

Rebase the branch so that the history is linear and clean.

# Conflicts:
#	.github/workflows/e2e-tests.yml
# Conflicts:
#	src/Dependency/DependencyResolver.php
@ondrejmirtes
ondrejmirtes merged commit 692eeee into phpstan:2.2.x Sep 3, 2026
300 of 308 checks passed
@ondrejmirtes

Copy link
Copy Markdown
Member

Thank you!

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