From 642e2bbda79545ad3ed7e0b0e5d1a4b7cec8b7c0 Mon Sep 17 00:00:00 2001 From: Sebastian Bergmann Date: Sat, 1 Aug 2026 09:45:25 +0200 Subject: [PATCH] Introduce Exporter::hasCustomRepresentationFor() for checking whether an object exporter provides the representation for an object --- ChangeLog.md | 1 + README.md | 19 +++++++++++++++++++ src/Exporter.php | 20 ++++++++++++++++++++ tests/ExporterTest.php | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 6456082..b0c5a11 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -8,6 +8,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt * `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) * `Exporter::shortenedExport()` and `Exporter::shortenedRecursiveExport()` use the representation provided by an object exporter as well; it is collapsed to a single line and shortened when it is longer than the configured maximum length +* `Exporter::hasCustomRepresentationFor()` for checking whether an object exporter provides the representation for an object ## [8.1.1] - 2026-07-13 diff --git a/README.md b/README.md index b353939..4679fe7 100644 --- a/README.md +++ b/README.md @@ -334,3 +334,22 @@ print $exporter->shortenedExport(new Money(1999, 'EUR')); ``` Bear in mind that these representations are used where a short, single-line, and stable string is required. The representation of a data set is built using `Exporter::shortenedRecursiveExport()`, for instance, and is part of the name of a test that uses a data provider. An object exporter should therefore provide a representation that is compact and that does not change from one export to the next. + +### Custom Representations + +`Exporter::hasCustomRepresentationFor()` tells whether an object exporter provides the representation for an object. This is meant for code that renders objects itself and wants to use the representation an object exporter provides when there is one: + +```php +hasCustomRepresentationFor(new Money(1999, 'EUR'))); + +// false +var_dump($exporter->hasCustomRepresentationFor(new stdClass)); +``` + +Bear in mind that an object that is (indirectly) nested in itself is replaced with a reference to the object instead of being exported by an object exporter again. diff --git a/src/Exporter.php b/src/Exporter.php index 9a6306d..45447d0 100644 --- a/src/Exporter.php +++ b/src/Exporter.php @@ -202,6 +202,26 @@ final readonly class Exporter return $this->export($value); } + /** + * Returns whether a custom object exporter provides the representation + * for an object. + * + * This is intended for code that renders objects itself and wants to use + * the representation a custom object exporter provides when there is one. + * + * Bear in mind that an object that is (indirectly) nested in itself is + * replaced with a reference to the object instead of being exported by a + * custom object exporter again. + */ + public function hasCustomRepresentationFor(object $object): bool + { + if ($this->objectExporter === null) { + return false; + } + + return $this->objectExporter->handles($object); + } + /** * Converts an object to an array containing all of its private, protected * and public properties. diff --git a/tests/ExporterTest.php b/tests/ExporterTest.php index 8720e5d..8cb7db7 100644 --- a/tests/ExporterTest.php +++ b/tests/ExporterTest.php @@ -939,6 +939,41 @@ EOT, ); } + public function testKnowsThatCustomObjectExporterProvidesRepresentationForObjectItHandles(): void + { + $exporter = new Exporter( + 0, + 40, + new ObjectExporterChain( + [ + new ObjectExporterThatHandlesObjectsOfSpecificType(ExampleClass::class), + ], + ), + ); + + $this->assertTrue($exporter->hasCustomRepresentationFor(new ExampleClass('bar'))); + } + + public function testKnowsThatCustomObjectExporterDoesNotProvideRepresentationForObjectItDoesNotHandle(): void + { + $exporter = new Exporter( + 0, + 40, + new ObjectExporterChain( + [ + new ObjectExporterThatHandlesObjectsOfSpecificType(ExampleClass::class), + ], + ), + ); + + $this->assertFalse($exporter->hasCustomRepresentationFor(new stdClass)); + } + + public function testKnowsThatNoCustomObjectExporterProvidesRepresentationForObjectWhenNoneIsConfigured(): void + { + $this->assertFalse((new Exporter)->hasCustomRepresentationFor(new stdClass)); + } + public function testCustomObjectExporterCanExportValuesNestedInObjectItHandles(): void { $exporter = new Exporter(