Ask custom object exporter for representation before consulting recursion context

This commit is contained in:
Sebastian Bergmann 2026-07-30 07:56:57 +02:00
parent 7e531fa24d
commit 5f9dc382bf
No known key found for this signature in database
2 changed files with 36 additions and 6 deletions

View File

@ -518,6 +518,15 @@ final readonly class Exporter
private function exportObject(object $value, RecursionContext $processed, int $indentation): string
{
// A custom object exporter is responsible for the entire
// representation of the object it handles. Therefore, it is asked for
// that representation before the recursion context is consulted: every
// occurrence of such an object is exported the same way instead of
// repeated occurrences being replaced with a reference to the object.
if ($this->objectExporter !== null && $this->objectExporter->handles($value)) {
return $this->objectExporter->export($value, $this, $indentation);
}
$class = $value::class;
if ($processed->contains($value) !== false) {
@ -526,10 +535,6 @@ final readonly class Exporter
$processed->add($value);
if ($this->objectExporter !== null && $this->objectExporter->handles($value)) {
return $this->objectExporter->export($value, $this, $indentation);
}
$array = $this->toArray($value);
$buffer = '';

View File

@ -716,7 +716,7 @@ EOT,
);
}
public function testObjectHandledByCustomObjectExporterIsOnlyExportedOnce(): void
public function testEveryOccurrenceOfObjectHandledByCustomObjectExporterIsExportedByThatObjectExporter(): void
{
$exporter = new Exporter(
0,
@ -730,10 +730,35 @@ EOT,
$object = new stdClass;
$this->assertStringMatchesFormat(
$this->assertSame(
<<<'EOT'
Array &0 [
0 => stdClass (indentation: 1),
1 => stdClass (indentation: 1),
]
EOT,
$exporter->export([$object, $object]),
);
}
public function testRepeatedOccurrenceOfObjectNotHandledByCustomObjectExporterIsReplacedWithReferenceToObject(): void
{
$exporter = new Exporter(
0,
40,
new ObjectExporterChain(
[
new ObjectExporterThatHandlesNoObject,
],
),
);
$object = new stdClass;
$this->assertStringMatchesFormat(
<<<'EOT'
Array &0 [
0 => stdClass Object #%d (),
1 => stdClass Object #%d,
]
EOT,