{"record":{"id":"fd9d777b5a97c4da","repo":"sebastianbergmann/phpunit","slug":"parameters-for-method-s-are-already-configured","errorCode":null,"errorMessage":"Parameters for method \"%s\" are already configured for another matcher. with() configures an expectation (the method must be called with the specified arguments), it does not select a return value based on arguments. Use willReturnMap() to return different values based on arguments.","messagePattern":"Parameters for method \"(.+?)\" are already configured for another matcher\\. with\\(\\) configures an expectation \\(the method must be called with the specified arguments\\), it does not select a return value based on arguments\\. Use willReturnMap\\(\\) to return different values based on arguments\\.","errorType":"exception","errorClass":"MethodParametersAlreadyConfiguredForAnotherMatcherException","httpStatus":null,"severity":"error","filePath":"src/Framework/MockObject/Runtime/InvocationMockerImplementation.php","lineNumber":130,"sourceCode":"     *\n     * @deprecated https://github.com/sebastianbergmann/phpunit/issues/6537\n     */\n    public function after(string $id): InvocationMocker\n    {\n        $this->matcher->setAfterMatchBuilderId($id);\n\n        return $this;\n    }\n\n    /**\n     * @throws MethodParametersAlreadyConfiguredForAnotherMatcherException\n     */\n    private function ensureNoOtherMatcherHasParametersRuleForSameMethod(): void\n    {\n        foreach ($this->configurableMethods as $method) {\n            if ($this->matcher->methodNameRule()->matchesName($method->name()) &&\n                $this->invocationHandler->hasMatcherWithParametersRuleForMethodName($this->matcher, $method->name())) {\n                throw new MethodParametersAlreadyConfiguredForAnotherMatcherException($method->name());\n            }\n        }\n    }\n\n    private function emitDeprecationWhenCreatedWithoutExplicitExpects(): void\n    {\n        if (!$this->createdWithoutExplicitExpects) {\n            return;\n        }\n\n        EventFacade::emitter()->testTriggeredPhpunitDeprecation(\n            null,\n            'Using with*() without expects() is deprecated and will no longer be possible in PHPUnit 14.',\n        );\n    }\n}\n","sourceCodeStart":112,"sourceCodeEnd":147,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/MockObject/Runtime/InvocationMockerImplementation.php#L112-L147","documentation":"Thrown by InvocationMockerImplementation when you call with() (or the parameter-set variants / withAnyParameters()) on a matcher whose method already has a parameters rule on a DIFFERENT matcher of the same double. In PHPUnit's model, with() declares 'the method must be called with these arguments' (an assertion), not 'return X for args Y', so two conflicting argument assertions for one method are rejected. The message points you to willReturnMap() for argument-dependent returns.","triggerScenarios":"$mock->expects($this->once())->method('get')->with(1)->willReturn('a'); $mock->expects($this->once())->method('get')->with(2)->willReturn('b'); — second with() for method 'get' throws. Also triggered by mixing with() with withParameterSetsInOrder()/withParameterSetsInAnyOrder()/withParameterSetsInPartialOrder()/withAnyParameters() for the same method on another matcher.","commonSituations":"Trying to express a lookup table (same method, different arguments, different returns) the way developers do in prophecy/mockery; migrating such tests to PHPUnit 10+ where this restriction is enforced; combining an argument assertion from a copied test with a newly written one for the same method.","solutions":["Use one matcher plus argument-dependent returns: ->method('get')->willReturnMap([[1, 'a'], [2, 'b']]).","Or use ->willReturnCallback(fn (int $id) => match ($id) { 1 => 'a', 2 => 'b' }).","If you truly need two separate argument assertions, keep them on different methods, or assert a parameter set once via withParameterSetsInAnyOrder([...]).","Remove a redundant withAnyParameters()/with() left over on an earlier matcher for the same method."],"exampleFix":"// before\n$cache = $this->createMock(Cache::class);\n$cache->expects($this->any())->method('get')->with('a')->willReturn(1);\n$cache->expects($this->any())->method('get')->with('b')->willReturn(2);\n\n// after\n$cache = $this->createMock(Cache::class);\n$cache->method('get')->willReturnMap([\n    ['a', 1],\n    ['b', 2],\n]);","handlingStrategy":"validation","validationCode":"// one argument assertion per method: encode lookup tables as maps instead\n$cases = [[1, 'a'], [2, 'b']];\n$mock->method('get')->willReturnMap($cases); // no second with() needed","typeGuard":"function assertSingleWithPerMethod(array $expectationsByMethod): bool\n{\n    foreach (array_count_values(array_keys($expectationsByMethod)) as $count) {\n        if ($count > 1) {\n            return false;\n        }\n    }\n\n    return true;\n}","tryCatchPattern":"try {\n    $mock->expects($this->once())->method('get')->with(2)->willReturn('b');\n} catch (PHPUnit\\Framework\\MockObject\\MethodParametersAlreadyConfiguredForAnotherMatcherException $e) {\n    // merge both argument cases into willReturnMap() on the existing matcher\n}","preventionTips":["Treat with() as an assertion, not a dispatch table — argument-dependent returns belong in willReturnMap()/willReturnCallback().","One with() (or one parameter-set rule) per method per double.","When migrating Mockery/Prophecy-style tests, rewrite per-argument expectations as maps immediately."],"tags":["phpunit","mock-object","with","expectations","willreturnmap"],"backgroundTag":"conflicting-mock-expectations","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}