Failed Conditions
Pull Request — develop (#6719)
by Marco
63:32
created

ProxyFactoryTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 267
Duplicated Lines 20.97 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 10
lcom 1
cbo 13
dl 56
loc 267
rs 10
c 1
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 19 1
B testReferenceProxyDelegatesLoadingToThePersister() 0 30 1
A testSkipAbstractClassesOnGeneration() 0 10 1
B testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized() 28 28 2
B testFailedProxyCloningDoesNotMarkTheProxyAsInitialized() 28 28 2
B testProxyClonesParentFields() 0 39 1
A testFriendObjectsDoNotLazyLoadIfNotAccessingLazyState() 0 20 1
B testFriendObjectsLazyLoadWhenAccessingLazyState() 0 46 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\ORM\Proxy;
6
7
use Doctrine\ORM\EntityNotFoundException;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Doctrine\ORM\Mapping\ClassMetadataBuildingContext;
10
use Doctrine\ORM\Mapping\ClassMetadataFactory;
11
use Doctrine\ORM\Persisters\Entity\BasicEntityPersister;
12
use Doctrine\ORM\Proxy\Factory\StaticProxyFactory;
13
use Doctrine\ORM\Reflection\RuntimeReflectionService;
14
use Doctrine\Tests\Mocks\ConnectionMock;
15
use Doctrine\Tests\Mocks\DriverMock;
16
use Doctrine\Tests\Mocks\EntityManagerMock;
17
use Doctrine\Tests\Mocks\UnitOfWorkMock;
18
use Doctrine\Tests\Models\Company\CompanyEmployee;
19
use Doctrine\Tests\Models\ECommerce\ECommerceFeature;
20
use Doctrine\Tests\Models\FriendObject\ComparableObject;
21
use Doctrine\Tests\OrmTestCase;
22
use ProxyManager\Proxy\GhostObjectInterface;
23
24
/**
25
 * Test the proxy generator. Its work is generating on-the-fly subclasses of a given model, which implement the Proxy pattern.
26
 * @author Giorgio Sironi <[email protected]>
27
 */
28
class ProxyFactoryTest extends OrmTestCase
29
{
30
    /**
31
     * @var ConnectionMock
32
     */
33
    private $connectionMock;
34
35
    /**
36
     * @var UnitOfWorkMock
37
     */
38
    private $uowMock;
39
40
    /**
41
     * @var EntityManagerMock
42
     */
43
    private $emMock;
44
45
    /**
46
     * @var StaticProxyFactory
47
     */
48
    private $proxyFactory;
49
50
    /**
51
     * @var ClassMetadataBuildingContext
52
     */
53
    private $metadataBuildingContext;
54
55
    /**
56
     * {@inheritDoc}
57
     */
58
    protected function setUp()
59
    {
60
        parent::setUp();
61
62
        $this->metadataBuildingContext = new ClassMetadataBuildingContext(
63
            $this->createMock(ClassMetadataFactory::class),
64
            new RuntimeReflectionService()
65
        );
66
        $this->connectionMock          = new ConnectionMock([], new DriverMock());
67
        $this->emMock                  = EntityManagerMock::create($this->connectionMock);
68
        $this->uowMock                 = new UnitOfWorkMock($this->emMock);
69
70
        $this->emMock->setUnitOfWork($this->uowMock);
71
72
        $this->proxyFactory = new StaticProxyFactory(
73
            $this->emMock,
74
            $this->emMock->getConfiguration()->buildGhostObjectFactory()
75
        );
76
    }
77
78
    public function testReferenceProxyDelegatesLoadingToThePersister()
79
    {
80
        $identifier    = ['id' => 42];
81
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
82
83
        $persister = $this
84
            ->getMockBuilder(BasicEntityPersister::class)
85
            ->setConstructorArgs([$this->emMock, $classMetaData])
86
            ->setMethods(['loadById'])
87
            ->getMock();
88
89
        $persister
90
            ->expects($this->atLeastOnce())
91
            ->method('loadById')
92
            ->with(
93
                $identifier,
94
                self::logicalAnd(
95
                    self::isInstanceOf(GhostObjectInterface::class),
96
                    self::isInstanceOf(ECommerceFeature::class)
97
                )
98
            )
99
            ->will($this->returnValue(new \stdClass()));
100
101
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
102
103
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
104
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, $identifier);
105
106
        $proxy->getDescription();
0 ignored issues
show
Bug introduced by
The method getDescription does only exist in Doctrine\Tests\Models\ECommerce\ECommerceFeature, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
107
    }
108
109
    /**
110
     * @group DDC-1771
111
     */
112
    public function testSkipAbstractClassesOnGeneration()
113
    {
114
        $cm = new ClassMetadata(AbstractClass::class, $this->metadataBuildingContext);
115
116
        self::assertNotNull($cm->getReflectionClass());
117
118
        $num = $this->proxyFactory->generateProxyClasses([$cm]);
119
120
        self::assertEquals(0, $num, "No proxies generated.");
121
    }
122
123
    /**
124
     * @group DDC-2432
125
     */
126 View Code Duplication
    public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized()
127
    {
128
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
129
130
        $persister = $this
131
            ->getMockBuilder(BasicEntityPersister::class)
132
            ->setConstructorArgs([$this->emMock, $classMetaData])
133
            ->setMethods(['load'])
134
            ->getMock();
135
136
        $persister
137
            ->expects($this->atLeastOnce())
138
            ->method('load')
139
            ->will($this->returnValue(null));
140
141
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
142
143
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
144
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
145
146
        try {
147
            $proxy->getDescription();
0 ignored issues
show
Bug introduced by
The method getDescription does only exist in Doctrine\Tests\Models\ECommerce\ECommerceFeature, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
148
            $this->fail('An exception was expected to be raised');
149
        } catch (EntityNotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
150
        }
151
152
        self::assertFalse($proxy->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\ECommerce\ECommerceFeature.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
153
    }
154
155
    /**
156
     * @group DDC-2432
157
     */
158 View Code Duplication
    public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized()
159
    {
160
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
161
162
        $persister = $this
163
            ->getMockBuilder(BasicEntityPersister::class)
164
            ->setConstructorArgs([$this->emMock, $classMetaData])
165
            ->setMethods(['load'])
166
            ->getMock();
167
168
        $persister
169
            ->expects($this->atLeastOnce())
170
            ->method('load')
171
            ->will($this->returnValue(null));
172
173
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
174
175
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
176
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
177
178
        try {
179
            $cloned = clone $proxy;
0 ignored issues
show
Unused Code introduced by
$cloned is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
180
            $this->fail('An exception was expected to be raised');
181
        } catch (EntityNotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
182
        }
183
184
        self::assertFalse($proxy->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\ECommerce\ECommerceFeature.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
185
    }
186
187
    public function testProxyClonesParentFields()
188
    {
189
        $identifier    = ['id' => 42];
190
        $classMetaData = $this->emMock->getClassMetadata(CompanyEmployee::class);
191
192
        $persister = $this
193
            ->getMockBuilder(BasicEntityPersister::class)
194
            ->setConstructorArgs([$this->emMock, $classMetaData])
195
            ->setMethods(['loadById'])
196
            ->getMock();
197
198
        $persister
199
            ->expects(self::atLeastOnce())
200
            ->method('loadById')
201
            ->with(
202
                $identifier,
203
                self::logicalAnd(
204
                    self::isInstanceOf(GhostObjectInterface::class),
205
                    self::isInstanceOf(CompanyEmployee::class)
206
                )
207
            )
208
            ->willReturnCallback(function (array $id, CompanyEmployee $companyEmployee) {
209
                $companyEmployee->setSalary(1000); // A property on the CompanyEmployee
210
                $companyEmployee->setName('Bob'); // A property on the parent class, CompanyPerson
211
212
                return $companyEmployee;
213
            });
214
215
        $this->uowMock->setEntityPersister(CompanyEmployee::class, $persister);
216
217
        /* @var $proxy GhostObjectInterface|CompanyEmployee */
218
        $proxy = $this->proxyFactory->getProxy(CompanyEmployee::class, $identifier);
219
220
        $cloned = clone $proxy;
221
222
        self::assertSame(42, $cloned->getId(), 'Expected the Id to be cloned');
0 ignored issues
show
Bug introduced by
The method getId does only exist in Doctrine\Tests\Models\Company\CompanyEmployee, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
223
        self::assertSame(1000, $cloned->getSalary(), 'Expect properties on the CompanyEmployee class to be cloned');
0 ignored issues
show
Bug introduced by
The method getSalary does only exist in Doctrine\Tests\Models\Company\CompanyEmployee, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
224
        self::assertSame('Bob', $cloned->getName(), 'Expect properties on the CompanyPerson class to be cloned');
0 ignored issues
show
Bug introduced by
The method getName does only exist in Doctrine\Tests\Models\Company\CompanyEmployee, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
225
    }
226
227
    public function testFriendObjectsDoNotLazyLoadIfNotAccessingLazyState()
228
    {
229
        /* @var $persister BasicEntityPersister|\PHPUnit_Framework_MockObject_MockObject */
230
        $persister = $this->createMock(BasicEntityPersister::class);
231
        $persister->expects(self::never())->method('loadById');
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Doctrine\ORM\Persisters\...ty\BasicEntityPersister.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
232
233
        $this->uowMock->setEntityPersister(ComparableObject::class, $persister);
0 ignored issues
show
Bug introduced by
It seems like $persister defined by $this->createMock(\Doctr...EntityPersister::class) on line 230 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, Doctrine\Tests\Mocks\Uni...k::setEntityPersister() does only seem to accept object<Doctrine\ORM\Pers...y\BasicEntityPersister>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
234
235
        /* @var $comparable ComparableObject|GhostObjectInterface */
236
        $comparable = $this->proxyFactory->getProxy(ComparableObject::class, ['id' => 123]);
237
238
        self::assertInstanceOf(ComparableObject::class, $comparable);
239
        self::assertInstanceOf(GhostObjectInterface::class, $comparable);
240
        self::assertFalse($comparable->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\Fr...Object\ComparableObject.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
241
242
        // due to implementation details, identity check is not reading lazy state:
243
        self::assertTrue($comparable->equalTo($comparable));
0 ignored issues
show
Documentation introduced by
$comparable is of type object<Doctrine\Tests\Mo...y\GhostObjectInterface>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method equalTo does only exist in Doctrine\Tests\Models\Fr...Object\ComparableObject, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
244
245
        self::assertFalse($comparable->isProxyInitialized());
246
    }
247
248
    public function testFriendObjectsLazyLoadWhenAccessingLazyState()
249
    {
250
        /* @var $persister BasicEntityPersister|\PHPUnit_Framework_MockObject_MockObject */
251
        $persister = $this
252
            ->getMockBuilder(BasicEntityPersister::class)
253
            ->setConstructorArgs([$this->emMock, $this->emMock->getClassMetadata(ComparableObject::class)])
254
            ->setMethods(['loadById'])
255
            ->getMock();
256
257
        $persister
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Doctrine\ORM\Persisters\...ty\BasicEntityPersister.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
258
            ->expects(self::exactly(2))
259
            ->method('loadById')
260
            ->with(
261
                self::logicalOr(['id' => 123], ['id' => 456]),
262
                self::logicalAnd(
263
                    self::isInstanceOf(GhostObjectInterface::class),
264
                    self::isInstanceOf(ComparableObject::class)
265
                )
266
            )
267
            ->willReturnCallback(function (array $id, ComparableObject $comparableObject) {
268
                $comparableObject->setComparedFieldValue(\json_encode($id));
269
270
                return $comparableObject;
271
            });
272
273
        $this->uowMock->setEntityPersister(ComparableObject::class, $persister);
274
275
        /* @var $comparable1 ComparableObject|GhostObjectInterface */
276
        $comparable1 = $this->proxyFactory->getProxy(ComparableObject::class, ['id' => 123]);
277
        /* @var $comparable2 ComparableObject|GhostObjectInterface */
278
        $comparable2 = $this->proxyFactory->getProxy(ComparableObject::class, ['id' => 456]);
279
280
        self::assertInstanceOf(ComparableObject::class, $comparable1);
281
        self::assertInstanceOf(ComparableObject::class, $comparable2);
282
        self::assertInstanceOf(GhostObjectInterface::class, $comparable1);
283
        self::assertInstanceOf(GhostObjectInterface::class, $comparable2);
284
        self::assertNotSame($comparable1, $comparable2);
285
        self::assertFalse($comparable1->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\Fr...Object\ComparableObject.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
286
        self::assertFalse($comparable2->isProxyInitialized());
287
288
        // due to implementation details, identity check is not reading lazy state:
289
        self::assertFalse($comparable1->equalTo($comparable2));
0 ignored issues
show
Documentation introduced by
$comparable2 is of type object<Doctrine\Tests\Mo...y\GhostObjectInterface>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
The method equalTo does only exist in Doctrine\Tests\Models\Fr...Object\ComparableObject, but not in ProxyManager\Proxy\GhostObjectInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
290
291
        self::assertTrue($comparable1->isProxyInitialized());
292
        self::assertTrue($comparable2->isProxyInitialized());
293
    }
294
}
295
296
abstract class AbstractClass
297
{
298
299
}
300