Accept any object exporter, not just a chain, in Exporter's constructor

This commit is contained in:
Sebastian Bergmann 2026-08-01 09:11:45 +02:00
parent b5aff00a52
commit 792150d027
No known key found for this signature in database
4 changed files with 36 additions and 12 deletions

View File

@ -6,7 +6,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
### Added
`ObjectExporter` interface, `ObjectExporterChain`, and `ExportContext` for customizing how objects are exported (a chain can be passed to `Exporter`'s constructor and is consulted before the default representation of an object is used)
`ObjectExporter` interface, `ObjectExporterChain`, and `ExportContext` for customizing how objects are exported (an object exporter can be passed to `Exporter`'s constructor and is consulted before the default representation of an object is used)
## [8.1.1] - 2026-07-13

View File

@ -202,16 +202,13 @@ final class MoneyExporter implements ObjectExporter
}
```
Object exporters are registered by passing an `ObjectExporterChain` to `Exporter`'s constructor. They are consulted, in the order in which they are composed into the chain, before the default representation of an object is used. The first object exporter whose `handles()` method returns `true` is asked for the representation:
An object exporter is registered by passing it to `Exporter`'s constructor. It is consulted before the default representation of an object is used:
```php
<?php declare(strict_types=1);
use SebastianBergmann\Exporter\Exporter;
use SebastianBergmann\Exporter\ObjectExporterChain;
$exporter = new Exporter(
objectExporter: new ObjectExporterChain([new MoneyExporter]),
);
$exporter = new Exporter(objectExporter: new MoneyExporter);
// Money (1999 EUR)
print $exporter->export(new Money(1999, 'EUR'));
@ -230,6 +227,23 @@ $price->gross = new Money(2379, 'EUR');
print $exporter->export($price);
```
`ObjectExporterChain` composes multiple object exporters into a single one. They are consulted in the order in which they are composed into the chain and the first one whose `handles()` method returns `true` is asked for the representation:
```php
<?php declare(strict_types=1);
use SebastianBergmann\Exporter\Exporter;
use SebastianBergmann\Exporter\ObjectExporterChain;
$exporter = new Exporter(
objectExporter: new ObjectExporterChain(
[
new BasketExporter,
new MoneyExporter,
],
),
);
```
Enums are objects and are therefore passed to the object exporters as well. When no object exporter handles an object, the default representation is used for it.
### Repeated Occurrences
@ -302,10 +316,6 @@ Array &0 [
]
*/
$exporter = new Exporter(
objectExporter: new ObjectExporterChain([new BasketExporter, new MoneyExporter]),
);
print $exporter->export(['basket' => new Basket([new Money(1999, 'EUR')])]);
```

View File

@ -61,13 +61,13 @@ final readonly class Exporter
* @var positive-int
*/
private int $maxLengthForStrings;
private ?ObjectExporterChain $objectExporter;
private ?ObjectExporter $objectExporter;
/**
* @param non-negative-int $shortenArraysLongerThan
* @param positive-int $maxLengthForStrings
*/
public function __construct(int $shortenArraysLongerThan = 0, int $maxLengthForStrings = 40, ?ObjectExporterChain $objectExporter = null)
public function __construct(int $shortenArraysLongerThan = 0, int $maxLengthForStrings = 40, ?ObjectExporter $objectExporter = null)
{
$this->shortenArraysLongerThan = $shortenArraysLongerThan;
$this->maxLengthForStrings = $maxLengthForStrings;

View File

@ -670,6 +670,20 @@ EOF;
);
}
public function testObjectCanBeExportedByCustomObjectExporterThatIsNotComposedIntoChain(): void
{
$exporter = new Exporter(
0,
40,
new ObjectExporterThatHandlesEveryObject,
);
$this->assertSame(
'stdClass (indentation: 0)',
$exporter->export(new stdClass),
);
}
public function testObjectNestedInArrayCanBeExportedByCustomObjectExporter(): void
{
$exporter = new Exporter(