Skip to content

Commit 2148940

Browse files
authored
Merge pull request #12335 from greg0ire/gh-12166
Avoid lazy object initialization when initializing read-only property
2 parents d353809 + e923bbc commit 2148940

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

src/Mapping/PropertyAccessors/ReadonlyAccessor.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
use function sprintf;
1212

13+
use const PHP_VERSION_ID;
14+
1315
/** @internal */
1416
class ReadonlyAccessor implements PropertyAccessor
1517
{
@@ -26,7 +28,12 @@ public function __construct(private PropertyAccessor $parent, private Reflection
2628

2729
public function setValue(object $object, mixed $value): void
2830
{
29-
if (! $this->reflectionProperty->isInitialized($object)) {
31+
/* For lazy properties, skip the isInitialized() check
32+
because it would trigger the initialization of the whole object. */
33+
if (
34+
PHP_VERSION_ID >= 80400 && $this->reflectionProperty->isLazy($object)
35+
|| ! $this->reflectionProperty->isInitialized($object)
36+
) {
3037
$this->parent->setValue($object, $value);
3138

3239
return;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH12166;
6+
7+
use Doctrine\Tests\OrmFunctionalTestCase;
8+
9+
class GH12166Test extends OrmFunctionalTestCase
10+
{
11+
public function testProxyWithReadonlyIdIsNotInitializedImmediately(): void
12+
{
13+
$this->createSchemaForModels(LazyEntityWithReadonlyId::class);
14+
$this->_em->persist(new LazyEntityWithReadonlyId(123, 'Test Name'));
15+
$this->_em->flush();
16+
$this->_em->clear();
17+
$proxy = $this->_em->getReference(LazyEntityWithReadonlyId::class, 123);
18+
19+
$reflClass = $this->_em->getClassMetadata(LazyEntityWithReadonlyId::class)->reflClass;
20+
self::assertTrue(
21+
$this->isUninitializedObject($proxy),
22+
'Proxy should remain uninitialized after creation',
23+
);
24+
25+
$id = $proxy->getId();
26+
self::assertSame(123, $id);
27+
self::assertTrue(
28+
$this->isUninitializedObject($proxy),
29+
'Proxy should remain uninitialized after accessing ID',
30+
);
31+
}
32+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket\GH12166;
6+
7+
use Doctrine\ORM\Mapping\Column;
8+
use Doctrine\ORM\Mapping\Entity;
9+
use Doctrine\ORM\Mapping\Id;
10+
use Doctrine\ORM\Mapping\Table;
11+
12+
#[Entity]
13+
#[Table(name: 'gh12166_lazy_entity')]
14+
class LazyEntityWithReadonlyId
15+
{
16+
#[Column(type: 'integer')]
17+
#[Id]
18+
private readonly int $id;
19+
20+
#[Column(type: 'string')]
21+
private string $name;
22+
23+
public function __construct(int $id, string $name)
24+
{
25+
$this->id = $id;
26+
$this->name = $name;
27+
}
28+
29+
public function getId(): int
30+
{
31+
return $this->id;
32+
}
33+
34+
public function getName(): string
35+
{
36+
return $this->name;
37+
}
38+
39+
public function setName(string $name): void
40+
{
41+
$this->name = $name;
42+
}
43+
}

0 commit comments

Comments
 (0)