From cfd44b878edabaf0ecec41f4a67ba8644f10e43e Mon Sep 17 00:00:00 2001 From: Samuel Akopyan Date: Mon, 8 Dec 2025 23:31:11 +0200 Subject: [PATCH 1/4] Refactored `ppd` function for improved CLI test handling with conditional exit strategy --- CHANGELOG.md | 3 +++ src/functions.php | 16 ++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 198bc84..755434d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +0.5.0 / + - Refactored `ppd` function for improved CLI test handling with conditional exit strategy + 0.4.3 / 2025-12-05 - Default precision increased from 2 to 4 - Refactor `PrettyPrint` for modularity: extract formatting logic into dedicated private methods diff --git a/src/functions.php b/src/functions.php index bcd953d..0afb74f 100644 --- a/src/functions.php +++ b/src/functions.php @@ -4,6 +4,7 @@ namespace { + use Apphp\PrettyPrint\Env; use Apphp\PrettyPrint\PrettyPrint; /** @@ -29,16 +30,19 @@ function pp(...$args): string /** * Alias for pprint with exit after printing * @param ...$args - * @return string */ - function ppd(...$args): string + function ppd(...$args) { - return pprint(...$args); + $exiter = null; - if (PHP_SAPI === 'cli' && getenv('APP_ENV') === 'test') { - return ''; + if (Env::isCli() && getenv('APP_ENV') === 'test') { + $exiter = fn() => null; } - exit; + $exiter ??= fn() => exit; + + // Execute behavior + pprint(...$args); + $exiter(); } } From ae43ac1e41afd5ebc1503735679ae5e333bd50e9 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan Date: Mon, 8 Dec 2025 23:42:31 +0200 Subject: [PATCH 2/4] Add support for automatic object-to-array conversion in `PrettyPrint` (`asArray()`/`toArray()`) and corresponding tests. --- CHANGELOG.md | 1 + README.md | 25 ++++++++++++++++++++++++ src/PrettyPrint.php | 18 ++++++++++++++---- tests/FunctionsTest.php | 36 +++++++++++++++++++++++++++++++++++ tests/PrettyPrintTest.php | 40 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 755434d..28b6705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 0.5.0 / - Refactored `ppd` function for improved CLI test handling with conditional exit strategy + - Added support for automatic object-to-array conversion in `PrettyPrint` (`asArray()`/`toArray()`) 0.4.3 / 2025-12-05 - Default precision increased from 2 to 4 diff --git a/README.md b/README.md index 4f01428..e6a58e9 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,31 @@ $pp($tensor3d, headB: 2, tailB: 1, headRows: 1, tailRows: 1, headCols: 1, tailCo $pp('Metrics:', [[0.91, 0.02], [0.03, 0.88]]); ``` +### Objects with `asArray()` / `toArray()` + +If you pass an object that exposes an `asArray()` or `toArray()` method, `pprint` / `PrettyPrint` will automatically convert it to an array before formatting: + +```php +class UserCollection +{ + public function asArray(): array + { + return [ + ['id' => 1, 'name' => 'Alice'], + ['id' => 2, 'name' => 'Bob'], + ]; + } +} + +$users = new UserCollection(); + +pprint($users); +// [[1, 'Alice'], +// [2, 'Bob']] +``` + +If `asArray()` is not present but `toArray()` is, `toArray()` will be used instead. + ## Running tests ```bash diff --git a/src/PrettyPrint.php b/src/PrettyPrint.php index ff41711..db3c28b 100644 --- a/src/PrettyPrint.php +++ b/src/PrettyPrint.php @@ -249,6 +249,18 @@ private function normalizeArgs(array $args): array } } $args = array_values($args); + + // Convert objects to arrays if possible + foreach ($args as $i => $value) { + if (is_object($value)) { + if (is_callable([$value, 'asArray'])) { + $args[$i] = $value->asArray(); + } elseif (is_callable([$value, 'toArray'])) { + $args[$i] = $value->toArray(); + } + } + } + if (count($args) > self::MAX_ARGS) { $args = array_slice($args, 0, self::MAX_ARGS); } @@ -263,8 +275,7 @@ private function normalizeArgs(array $args): array * @param array $fmt * @param string $start * @param string $end - * @param int $prevPrecision - * @return bool True if handled, false otherwise + * @return string|null True if handled, false otherwise */ private function tryLabel3D(array $args, array $fmt, string $start, string $end): ?string { @@ -292,8 +303,7 @@ private function tryLabel3D(array $args, array $fmt, string $start, string $end) * @param array $args * @param string $start * @param string $end - * @param int $prevPrecision - * @return bool True if handled, false otherwise + * @return string|null True if handled, false otherwise */ private function tryLabel2D(array $args, string $start, string $end): ?string { diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index 146b5e6..d60d48b 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -47,4 +47,40 @@ public function ppdPrintsThenExits(): void $this->expectOutputString("hello\n"); ppd('hello'); } + + #[Test] + #[TestDox('pprint uses asArray() when object provides it')] + public function pprintUsesAsArrayOnObject(): void + { + $obj = new class { + public function asArray(): array + { + return [1, 2, 3]; + } + }; + + ob_start(); + pprint($obj); + $out = ob_get_clean(); + + self::assertSame("[1, 2, 3]\n", $out); + } + + #[Test] + #[TestDox('pprint falls back to toArray() when object has no asArray()')] + public function pprintUsesToArrayOnObject(): void + { + $obj = new class { + public function toArray(): array + { + return ['a' => 1, 'b' => 2]; + } + }; + + ob_start(); + pprint($obj); + $out = ob_get_clean(); + + self::assertSame("[1, 2]\n", $out); + } } diff --git a/tests/PrettyPrintTest.php b/tests/PrettyPrintTest.php index 689facc..c5f3acb 100644 --- a/tests/PrettyPrintTest.php +++ b/tests/PrettyPrintTest.php @@ -514,4 +514,44 @@ public function defaultFormatterUsesFormatForArrayFor1D(): void $out = ob_get_clean(); self::assertSame("[1, 2, 3]\n", $out); } + + #[Test] + #[TestDox('converts objects with asArray() to arrays before formatting')] + public function convertsObjectWithAsArrayToArray(): void + { + $pp = new PrettyPrint(); + + $obj = new class { + public function asArray(): array + { + return [10, 20, 30]; + } + }; + + ob_start(); + $pp($obj); + $out = ob_get_clean(); + + self::assertSame("[10, 20, 30]\n", $out); + } + + #[Test] + #[TestDox('converts objects with toArray() to arrays when asArray() is not available')] + public function convertsObjectWithToArrayToArray(): void + { + $pp = new PrettyPrint(); + + $obj = new class { + public function toArray(): array + { + return ['x' => 5, 'y' => 6]; + } + }; + + ob_start(); + $pp($obj); + $out = ob_get_clean(); + + self::assertSame("[5, 6]\n", $out); + } } From dbb66ebd0780016a2453ce423e7ae41c3ceab2b3 Mon Sep 17 00:00:00 2001 From: Samuel Akopyan Date: Mon, 8 Dec 2025 23:55:08 +0200 Subject: [PATCH 3/4] Add namespace declaration to global helper functions and update corresponding tests and documentation. --- CHANGELOG.md | 1 + README.md | 14 ++++++++ src/functions.php | 76 ++++++++++++++++++++--------------------- tests/FunctionsTest.php | 9 ++--- 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28b6705..7af394c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 0.5.0 / - Refactored `ppd` function for improved CLI test handling with conditional exit strategy - Added support for automatic object-to-array conversion in `PrettyPrint` (`asArray()`/`toArray()`) + - Added namespace declaration to global helper functions 0.4.3 / 2025-12-05 - Default precision increased from 2 to 4 diff --git a/README.md b/README.md index e6a58e9..af37473 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,20 @@ composer require apphp/pretty-print Note: When used in web (non-CLI) environments, output is automatically wrapped in `
` to preserve spacing. In CLI, no wrapping is applied. When you request a string to be returned (see `return` option), no auto-wrapping is applied.
 
+### Import functions
+
+All examples below assume you have imported the helper functions from the `Apphp\PrettyPrint` namespace, for example:
+
+```php
+use function Apphp\PrettyPrint\pprint;
+use function Apphp\PrettyPrint\pp;
+use function Apphp\PrettyPrint\ppd;
+```
+or simply
+```php
+use function Apphp\PrettyPrint\{pprint, pp, ppd};
+```
+
 ### Global helper functions
 
 Print scalars/strings
diff --git a/src/functions.php b/src/functions.php
index 0afb74f..10cd2f2 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -2,47 +2,47 @@
 
 declare(strict_types=1);
 
-namespace {
-
-    use Apphp\PrettyPrint\Env;
-    use Apphp\PrettyPrint\PrettyPrint;
-
-    /**
-     * Convenience wrapper around PrettyPrint's callable interface.
-     * @param ...$args
-     * @return string
-     */
-    function pprint(...$args): string
-    {
-        return (new PrettyPrint())(...$args);
-    }
+namespace Apphp\PrettyPrint;
+
+use Apphp\PrettyPrint\Env;
+use Apphp\PrettyPrint\PrettyPrint;
+
+/**
+ * Convenience wrapper around PrettyPrint's callable interface.
+ * @param ...$args
+ * @return string
+ */
+function pprint(...$args): string
+{
+    return (new PrettyPrint())(...$args);
+}
 
-    /**
-     * Alias for pprint
-     * @param ...$args
-     * @return string
-     */
-    function pp(...$args): string
-    {
-        return pprint(...$args);
-    }
+/**
+ * Alias for pprint
+ * @param ...$args
+ * @return string
+ */
+function pp(...$args): string
+{
+    return pprint(...$args);
+}
 
-    /**
-     * Alias for pprint with exit after printing
-     * @param ...$args
-     */
-    function ppd(...$args)
-    {
-        $exiter = null;
+/**
+ * Alias for pprint with exit after printing
+ * @param ...$args
+ */
+function ppd(...$args)
+{
+    $exiter = null;
 
-        if (Env::isCli() && getenv('APP_ENV') === 'test') {
-            $exiter = fn() => null;
-        }
+    if (Env::isCli() && getenv('APP_ENV') === 'test') {
+        $exiter = fn() => null;
+    }
 
-        $exiter ??= fn() => exit;
+    $exiter ??= fn() => exit;
 
-        // Execute behavior
-        pprint(...$args);
-        $exiter();
-    }
+    // Execute behavior
+    pprint(...$args);
+    $exiter();
 }
+
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index d60d48b..ee89131 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -11,11 +11,12 @@
 use PHPUnit\Framework\Attributes\CoversFunction;
 use PHPUnit\Framework\Attributes\RunInSeparateProcess;
 use PHPUnit\Framework\Attributes\PreserveGlobalState;
+use function Apphp\PrettyPrint\{pprint, pp, ppd};
 
-#[Group('prettyprint')]
-#[CoversFunction('pprint')]
-#[CoversFunction('pp')]
-#[CoversFunction('ppd')]
+#[Group('PrettyPrint')]
+#[CoversFunction('Apphp\\PrettyPrint\\pprint')]
+#[CoversFunction('Apphp\\PrettyPrint\\pp')]
+#[CoversFunction('Apphp\\PrettyPrint\\ppd')]
 final class FunctionsTest extends TestCase
 {
     #[Test]

From 1934f7a645c9cb068370c08c681cccb78418199a Mon Sep 17 00:00:00 2001
From: Samuel Akopyan 
Date: Mon, 8 Dec 2025 23:55:27 +0200
Subject: [PATCH 4/4] Version update

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7af394c..8613f00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-0.5.0 / 
+0.5.0 / 2025-12-08
  - Refactored `ppd` function for improved CLI test handling with conditional exit strategy    
  - Added support for automatic object-to-array conversion in `PrettyPrint` (`asArray()`/`toArray()`)
  - Added namespace declaration to global helper functions