Failed Conditions
Pull Request — develop (#6719)
by Marco
65:21
created

testReferenceProxyDelegatesLoadingToThePersister()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 30
rs 8.8571
c 1
b 0
f 0
cc 1
eloc 20
nc 1
nop 0
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\Models\ProxySpecifics\FuncGetArgs;
22
use Doctrine\Tests\OrmTestCase;
23
use ProxyManager\Proxy\GhostObjectInterface;
24
25
/**
26
 * Test the proxy generator. Its work is generating on-the-fly subclasses of a given model, which implement the Proxy pattern.
27
 * @author Giorgio Sironi <[email protected]>
28
 */
29
class ProxyFactoryTest extends OrmTestCase
30
{
31
    /**
32
     * @var ConnectionMock
33
     */
34
    private $connectionMock;
35
36
    /**
37
     * @var UnitOfWorkMock
38
     */
39
    private $uowMock;
40
41
    /**
42
     * @var EntityManagerMock
43
     */
44
    private $emMock;
45
46
    /**
47
     * @var StaticProxyFactory
48
     */
49
    private $proxyFactory;
50
51
    /**
52
     * @var ClassMetadataBuildingContext
53
     */
54
    private $metadataBuildingContext;
55
56
    /**
57
     * {@inheritDoc}
58
     */
59
    protected function setUp()
60
    {
61
        parent::setUp();
62
63
        $this->metadataBuildingContext = new ClassMetadataBuildingContext(
64
            $this->createMock(ClassMetadataFactory::class),
65
            new RuntimeReflectionService()
66
        );
67
        $this->connectionMock          = new ConnectionMock([], new DriverMock());
68
        $this->emMock                  = EntityManagerMock::create($this->connectionMock);
69
        $this->uowMock                 = new UnitOfWorkMock($this->emMock);
70
71
        $this->emMock->setUnitOfWork($this->uowMock);
72
73
        $this->proxyFactory = new StaticProxyFactory(
74
            $this->emMock,
75
            $this->emMock->getConfiguration()->buildGhostObjectFactory()
76
        );
77
    }
78
79
    public function testReferenceProxyDelegatesLoadingToThePersister()
80
    {
81
        $identifier    = ['id' => 42];
82
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
83
84
        $persister = $this
85
            ->getMockBuilder(BasicEntityPersister::class)
86
            ->setConstructorArgs([$this->emMock, $classMetaData])
87
            ->setMethods(['loadById'])
88
            ->getMock();
89
90
        $persister
91
            ->expects($this->atLeastOnce())
92
            ->method('loadById')
93
            ->with(
94
                $identifier,
95
                self::logicalAnd(
96
                    self::isInstanceOf(GhostObjectInterface::class),
97
                    self::isInstanceOf(ECommerceFeature::class)
98
                )
99
            )
100
            ->will($this->returnValue(new \stdClass()));
101
102
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
103
104
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
105
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, $identifier);
106
107
        $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...
108
    }
109
110
    /**
111
     * @group DDC-1771
112
     */
113
    public function testSkipAbstractClassesOnGeneration()
114
    {
115
        $cm = new ClassMetadata(AbstractClass::class, $this->metadataBuildingContext);
116
117
        self::assertNotNull($cm->getReflectionClass());
118
119
        $num = $this->proxyFactory->generateProxyClasses([$cm]);
120
121
        self::assertEquals(0, $num, "No proxies generated.");
122
    }
123
124
    /**
125
     * @group DDC-2432
126
     */
127 View Code Duplication
    public function testFailedProxyLoadingDoesNotMarkTheProxyAsInitialized()
128
    {
129
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
130
131
        $persister = $this
132
            ->getMockBuilder(BasicEntityPersister::class)
133
            ->setConstructorArgs([$this->emMock, $classMetaData])
134
            ->setMethods(['load'])
135
            ->getMock();
136
137
        $persister
138
            ->expects($this->atLeastOnce())
139
            ->method('load')
140
            ->will($this->returnValue(null));
141
142
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
143
144
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
145
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
146
147
        try {
148
            $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...
149
            $this->fail('An exception was expected to be raised');
150
        } catch (EntityNotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
151
        }
152
153
        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...
154
    }
155
156
    /**
157
     * @group DDC-2432
158
     */
159 View Code Duplication
    public function testFailedProxyCloningDoesNotMarkTheProxyAsInitialized()
160
    {
161
        $classMetaData = $this->emMock->getClassMetadata(ECommerceFeature::class);
162
163
        $persister = $this
164
            ->getMockBuilder(BasicEntityPersister::class)
165
            ->setConstructorArgs([$this->emMock, $classMetaData])
166
            ->setMethods(['load'])
167
            ->getMock();
168
169
        $persister
170
            ->expects($this->atLeastOnce())
171
            ->method('load')
172
            ->will($this->returnValue(null));
173
174
        $this->uowMock->setEntityPersister(ECommerceFeature::class, $persister);
175
176
        /* @var $proxy GhostObjectInterface|ECommerceFeature */
177
        $proxy = $this->proxyFactory->getProxy(ECommerceFeature::class, ['id' => 42]);
178
179
        try {
180
            $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...
181
            $this->fail('An exception was expected to be raised');
182
        } catch (EntityNotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
183
        }
184
185
        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...
186
    }
187
188
    public function testProxyClonesParentFields()
189
    {
190
        $identifier    = ['id' => 42];
191
        $classMetaData = $this->emMock->getClassMetadata(CompanyEmployee::class);
192
193
        $persister = $this
194
            ->getMockBuilder(BasicEntityPersister::class)
195
            ->setConstructorArgs([$this->emMock, $classMetaData])
196
            ->setMethods(['loadById'])
197
            ->getMock();
198
199
        $persister
200
            ->expects(self::atLeastOnce())
201
            ->method('loadById')
202
            ->with(
203
                $identifier,
204
                self::logicalAnd(
205
                    self::isInstanceOf(GhostObjectInterface::class),
206
                    self::isInstanceOf(CompanyEmployee::class)
207
                )
208
            )
209
            ->willReturnCallback(function (array $id, CompanyEmployee $companyEmployee) {
210
                $companyEmployee->setSalary(1000); // A property on the CompanyEmployee
211
                $companyEmployee->setName('Bob'); // A property on the parent class, CompanyPerson
212
213
                return $companyEmployee;
214
            });
215
216
        $this->uowMock->setEntityPersister(CompanyEmployee::class, $persister);
217
218
        /* @var $proxy GhostObjectInterface|CompanyEmployee */
219
        $proxy = $this->proxyFactory->getProxy(CompanyEmployee::class, $identifier);
220
221
        $cloned = clone $proxy;
222
223
        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...
224
        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...
225
        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...
226
    }
227
228
    public function testFriendObjectsDoNotLazyLoadIfNotAccessingLazyState()
229
    {
230
        /* @var $persister BasicEntityPersister|\PHPUnit_Framework_MockObject_MockObject */
231
        $persister = $this->createMock(BasicEntityPersister::class);
232
        $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...
233
234
        $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 231 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...
235
236
        /* @var $comparable ComparableObject|GhostObjectInterface */
237
        $comparable = $this->proxyFactory->getProxy(ComparableObject::class, ['id' => 123]);
238
239
        self::assertInstanceOf(ComparableObject::class, $comparable);
240
        self::assertInstanceOf(GhostObjectInterface::class, $comparable);
241
        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...
242
243
        // due to implementation details, identity check is not reading lazy state:
244
        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...
245
246
        self::assertFalse($comparable->isProxyInitialized());
247
    }
248
249
    public function testFriendObjectsLazyLoadWhenAccessingLazyState()
250
    {
251
        /* @var $persister BasicEntityPersister|\PHPUnit_Framework_MockObject_MockObject */
252
        $persister = $this
253
            ->getMockBuilder(BasicEntityPersister::class)
254
            ->setConstructorArgs([$this->emMock, $this->emMock->getClassMetadata(ComparableObject::class)])
255
            ->setMethods(['loadById'])
256
            ->getMock();
257
258
        $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...
259
            ->expects(self::exactly(2))
260
            ->method('loadById')
261
            ->with(
262
                self::logicalOr(['id' => 123], ['id' => 456]),
263
                self::logicalAnd(
264
                    self::isInstanceOf(GhostObjectInterface::class),
265
                    self::isInstanceOf(ComparableObject::class)
266
                )
267
            )
268
            ->willReturnCallback(function (array $id, ComparableObject $comparableObject) {
269
                $comparableObject->setComparedFieldValue(\json_encode($id));
270
271
                return $comparableObject;
272
            });
273
274
        $this->uowMock->setEntityPersister(ComparableObject::class, $persister);
275
276
        /* @var $comparable1 ComparableObject|GhostObjectInterface */
277
        $comparable1 = $this->proxyFactory->getProxy(ComparableObject::class, ['id' => 123]);
278
        /* @var $comparable2 ComparableObject|GhostObjectInterface */
279
        $comparable2 = $this->proxyFactory->getProxy(ComparableObject::class, ['id' => 456]);
280
281
        self::assertInstanceOf(ComparableObject::class, $comparable1);
282
        self::assertInstanceOf(ComparableObject::class, $comparable2);
283
        self::assertInstanceOf(GhostObjectInterface::class, $comparable1);
284
        self::assertInstanceOf(GhostObjectInterface::class, $comparable2);
285
        self::assertNotSame($comparable1, $comparable2);
286
        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...
287
        self::assertFalse($comparable2->isProxyInitialized());
288
289
        self::assertFalse(
290
            $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...
291
            'Due to implementation details, identity check is not reading lazy state'
292
        );
293
294
        self::assertTrue($comparable1->isProxyInitialized());
295
        self::assertTrue($comparable2->isProxyInitialized());
296
    }
297
298
    public function testProxyMethodsSupportFuncGetArgsLogic()
299
    {
300
        /* @var $persister BasicEntityPersister|\PHPUnit_Framework_MockObject_MockObject */
301
        $persister = $this->createMock(BasicEntityPersister::class);
302
        $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...
303
304
        $this->uowMock->setEntityPersister(FuncGetArgs::class, $persister);
0 ignored issues
show
Bug introduced by
It seems like $persister defined by $this->createMock(\Doctr...EntityPersister::class) on line 301 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...
305
306
        /* @var $funcGetArgs FuncGetArgs|GhostObjectInterface */
307
        $funcGetArgs = $this->proxyFactory->getProxy(FuncGetArgs::class, ['id' => 123]);
308
309
        self::assertInstanceOf(GhostObjectInterface::class, $funcGetArgs);
310
        self::assertFalse($funcGetArgs->isProxyInitialized());
0 ignored issues
show
Bug introduced by
The method isProxyInitialized does only exist in ProxyManager\Proxy\GhostObjectInterface, but not in Doctrine\Tests\Models\ProxySpecifics\FuncGetArgs.

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...
311
312
        self::assertSame(
313
            [1, 2, 3, 4],
314
            $funcGetArgs->funcGetArgsCallingMethod(1, 2, 3, 4),
0 ignored issues
show
Bug introduced by
The method funcGetArgsCallingMethod does only exist in Doctrine\Tests\Models\ProxySpecifics\FuncGetArgs, 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...
315
            '`func_get_args()` calls are now supported in proxy implementations'
316
        );
317
318
        self::assertFalse($funcGetArgs->isProxyInitialized(), 'No state was accessed anyway');
319
    }
320
}
321
322
abstract class AbstractClass
323
{
324
325
}
326