Skip to content

[12.x] Support string abstract in mock/partialMock/spy PHPDoc - #59477

Merged
taylorotwell merged 2 commits into
laravel:12.xfrom
kayw-geek:fix/mock-phpdoc-string-abstract
Apr 1, 2026
Merged

taylorotwell merged 2 commits into
laravel:12.xfrom
kayw-geek:fix/mock-phpdoc-string-abstract

Conversation

@kayw-geek

@kayw-geek kayw-geek commented Apr 1, 2026 •

Copy link
Copy Markdown
Contributor

This is a follow-up to #59353.

While #59353 improved the return type for mock(), partialMock(), and spy() when using class-string, it restricted the $abstract parameter to only accept class-string<TInstance>, which causes PHPStan errors when passing plain string aliases — a common pattern in Laravel:

$this->app->bind('my.service', fn () => new MyService());

// PHPStan error: Parameter #1 $abstract expects class-string<my.service>, 'my.service' given
$this->mock('my.service', function ($mock) {
    $mock->shouldReceive('doSomething')->andReturn(true);
});

This PR updates the @param to string|class-string<TInstance> and uses conditional return types (consistent with Container::make(), Container::makeWith(), etc.) so that:

Also adds PHPStan type assertion tests to verify both cases.

@kayw-geek kayw-geek changed the title Support string abstract in mock/partialMock/spy PHPDoc [12.x] Support string abstract in mock/partialMock/spy PHPDoc Apr 1, 2026
@AJenbo

AJenbo commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Thanks, sorry for the oversigt.

Can I ask why someone would use a string alias and type checking at the same time, it seems counter intuitive to me, and I'm working on two projects that aims to improve use and inference of types (a LSP for IDEs with build in Laravel support, and a Laravel plugin for mago, a fast Rust based alternative to PHPStan).

I would have thought anyone using the alias would not care about the type since it doesn't allow for anything meaningful on the other end?

@kayw-geek

Copy link
Copy Markdown
Contributor Author

Good question — adding string isn't about giving alias users better type inference
(there's nothing useful to infer, as you said).

It's just about not breaking their code: without it, passing 'my.service' would cause a PHPStan error like "expects class-string, string given."
The conditional return type simply means: infer when we can, fall back gracefully when we can't.

@taylorotwell
taylorotwell merged commit 79c3dc6 into laravel:12.x Apr 1, 2026
70 checks passed
@AJenbo

AJenbo commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Good question — 🤖

jonagoldman pushed a commit to deplox/laravel-framework that referenced this pull request Apr 30, 2026
…l#59477)

* Support string abstract in mock/partialMock/spy PHPDoc with conditional return types

* Fix StyleCI formatting
binaryfire added a commit to hypervel/components-backup that referenced this pull request Oct 1, 2026
- mock(), partialMock() and spy() return MockInterface&TInstance for a
  class-string and MockInterface for other container keys
  (laravel/framework#59353,
  laravel/framework#59384,
  laravel/framework#59477), with the upstream
  type fixture.
- The events dispatcher reads attributes through the support package's
  ReadsClassAttributes instead of the queue trait
  (laravel/framework#59275). The events package
  still requires hypervel/queue because CallQueuedListener uses it.
- env:encrypt and env:decrypt build paths from environmentPath()
  (laravel/framework#58984).
- Drop redundant array_flip() calls on class_uses_recursive(), which is
  already class-keyed (laravel/framework#59452),
  including Hypervel's command trait setup and Testbench's trait cache.
- JSON:API imports its base collection under an alias and documents a
  non-negative relationship depth
  (laravel/framework#59079). The flushState test
  uses the upstream name and values
  (laravel/framework#59116).
- Docblocks: Request::getSession() throws SessionNotFoundException
  (laravel/framework#58965), RateLimiter::for()
  (laravel/framework#59144) and
  WithoutOverlapping::shared()
  (laravel/framework#59375).
- Tests: the chained-batch queue test for a batch with only a connection
  (laravel/framework#59233), and the final
  response-limit assertion in the Redis throttle test
  (laravel/framework#58990).

Validation: each changed test file passes, as do the events, console,
environment command, JSON:API resource and type fixture checks.

Claude-Session: https://claude.ai/code/session_01WveaB7yyFo2T6yo7cnEpW9
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