Can't check for object identity with Argument::is() if they are weakly equal
Author: jnvsorCreated Apr 15, 2018Updated Oct 7, 2025
When mocking a method Argument::is can't be used to distinguish objects that are weakly identical.
Since identity is the whole point of Argument::is over Argument::exact for objects, this is rather annoying.
If I had to guess the source of the problem is in the assertEquals in ObjectProphecy::__call, since the additional prophecies aren't even registered.
Here's an example:
<?php
use Prophecy\Prophet;
use Prophecy\Argument;
require 'vendor/autoload.php';
$p = new Prophet();
$dt1 = new DateTime();
$dt2 = clone $dt1;
$dt3 = clone $dt1;
class TestClass {
public function methodCall()
{
}
}
$prophecyObject = $p->prophesize('TestClass');
// Argument::exact doesn't work because the properties have the same values
$prophecyObject->methodCall(Argument::exact($dt1))->shouldBeCalledTimes(1);
$prophecyObject->methodCall(Argument::exact($dt2))->shouldBeCalledTimes(1);
$prophecyObject->methodCall(Argument::exact($dt3))->shouldBeCalledTimes(1);
// Argument::is doesn't work because for some reason it flat out refuses to
// store more than one IdenticalValueToken even when called repeatedly
$prophecyObject->methodCall(Argument::is($dt1))->shouldBeCalledTimes(1);
$prophecyObject->methodCall(Argument::is($dt2))->shouldBeCalledTimes(1);
$prophecyObject->methodCall(Argument::is($dt3))->shouldBeCalledTimes(1);
// My current workaround
$prophecyObject->methodCall(
Argument::that(function ($arg) use ($dt1) {
return $arg === $dt1;
})
)->shouldBeCalledTimes(1);
$prophecyObject->methodCall(
Argument::that(function ($arg) use ($dt2) {
return $arg === $dt2;
})
)->shouldBeCalledTimes(1);
$prophecyObject->methodCall(
Argument::that(function ($arg) use ($dt3) {
return $arg === $dt3;
})
)->shouldBeCalledTimes(1);
$dummy = $prophecyObject->reveal();
$dummy->methodCall($dt1);
$dummy->methodCall($dt2);
$dummy->methodCall($dt3);
$p->checkPredictions();Source: phpspec/prophecy