first commit

This commit is contained in:
Claudecio Martins
2026-06-16 10:04:10 -03:00
commit a951944997
4463 changed files with 419677 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier;
interface Quoter
{
public function quote(string $string, int $depth): string;
}
+27
View File
@@ -0,0 +1,27 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Quoters;
use Respect\Stringifier\Quoter;
use function sprintf;
final class CodeQuoter implements Quoter
{
public function quote(string $string, int $depth): string
{
if ($depth === 0) {
return sprintf('`%s`', $string);
}
return $string;
}
}
+16
View File
@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier;
interface Stringifier
{
public function stringify(mixed $raw, int $depth): ?string;
}
@@ -0,0 +1,73 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function array_keys;
use function count;
use function implode;
use function is_array;
use function range;
use function sprintf;
final class ArrayStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier,
private readonly Quoter $quoter,
private readonly int $maximumDepth,
private readonly int $itemsLimit
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_array($raw)) {
return null;
}
if (empty($raw)) {
return $this->quoter->quote('{ }', $depth);
}
if ($depth >= $this->maximumDepth) {
return '...';
}
$items = [];
$itemsCount = 0;
$isSequential = $this->isSequential($raw);
foreach ($raw as $key => $value) {
if (++$itemsCount > $this->itemsLimit) {
$items[$itemsCount] = '...';
break;
}
$items[$itemsCount] = '';
if ($isSequential === false) {
$items[$itemsCount] .= sprintf('%s: ', $this->stringifier->stringify($key, $depth + 1));
}
$items[$itemsCount] .= $this->stringifier->stringify($value, $depth + 1);
}
return $this->quoter->quote(sprintf('{ %s }', implode(', ', $items)), $depth);
}
/**
* @param mixed[] $array
*/
private function isSequential(array $array): bool
{
return array_keys($array) === range(0, count($array) - 1);
}
}
@@ -0,0 +1,33 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function is_bool;
final class BoolStringifier implements Stringifier
{
public function __construct(
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_bool($raw)) {
return null;
}
return $this->quoter->quote($raw ? 'TRUE' : 'FALSE', $depth);
}
}
@@ -0,0 +1,85 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoters\CodeQuoter;
use Respect\Stringifier\Stringifier;
final class ClusterStringifier implements Stringifier
{
/**
* @var Stringifier[]
*/
private array $stringifiers = [];
/**
* @param Stringifier[] ...$stringifiers
*/
public function __construct(Stringifier ...$stringifiers)
{
$this->setStringifiers($stringifiers);
}
public static function createDefault(): self
{
$quoter = new CodeQuoter();
$stringifier = new self();
$stringifier->setStringifiers([
new TraversableStringifier($stringifier, $quoter),
new DateTimeStringifier($stringifier, $quoter, 'c'),
new ThrowableStringifier($stringifier, $quoter),
new StringableObjectStringifier($stringifier),
new JsonSerializableStringifier($stringifier, $quoter),
new ObjectStringifier($stringifier, $quoter),
new ArrayStringifier($stringifier, $quoter, 3, 5),
new InfiniteStringifier($quoter),
new NanStringifier($quoter),
new ResourceStringifier($quoter),
new BoolStringifier($quoter),
new NullStringifier($quoter),
new JsonParsableStringifier(),
]);
return $stringifier;
}
/**
* @param Stringifier[] $stringifiers
*/
public function setStringifiers(array $stringifiers): void
{
$this->stringifiers = [];
foreach ($stringifiers as $stringifier) {
$this->addStringifier($stringifier);
}
}
public function addStringifier(Stringifier $stringifier): void
{
$this->stringifiers[] = $stringifier;
}
public function stringify(mixed $raw, int $depth): ?string
{
foreach ($this->stringifiers as $stringifier) {
$string = $stringifier->stringify($raw, $depth);
if ($string === null) {
continue;
}
return $string;
}
return null;
}
}
@@ -0,0 +1,43 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use DateTimeInterface;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function sprintf;
final class DateTimeStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier,
private readonly Quoter $quoter,
private readonly string $format
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!$raw instanceof DateTimeInterface) {
return null;
}
return $this->quoter->quote(
sprintf(
'[date-time] (%s: %s)',
$raw::class,
$this->stringifier->stringify($raw->format($this->format), $depth + 1)
),
$depth
);
}
}
@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function is_float;
use function is_infinite;
final class InfiniteStringifier implements Stringifier
{
public function __construct(
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_float($raw)) {
return null;
}
if (!is_infinite($raw)) {
return null;
}
return $this->quoter->quote(($raw > 0 ? '' : '-') . 'INF', $depth);
}
}
@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Stringifier;
use function json_encode;
use const JSON_PRESERVE_ZERO_FRACTION;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;
final class JsonParsableStringifier implements Stringifier
{
public function stringify(mixed $raw, int $depth): ?string
{
$string = json_encode($raw, (JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION));
if ($string === false) {
return null;
}
return $string;
}
}
@@ -0,0 +1,42 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use JsonSerializable;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function sprintf;
final class JsonSerializableStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier,
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!$raw instanceof JsonSerializable) {
return null;
}
return $this->quoter->quote(
sprintf(
'[json-serializable] (%s: %s)',
$raw::class,
$this->stringifier->stringify($raw->jsonSerialize(), $depth + 1)
),
$depth
);
}
}
@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function is_float;
use function is_nan;
final class NanStringifier implements Stringifier
{
public function __construct(
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_float($raw)) {
return null;
}
if (!is_nan($raw)) {
return null;
}
return $this->quoter->quote('NaN', $depth);
}
}
@@ -0,0 +1,31 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
final class NullStringifier implements Stringifier
{
public function __construct(
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if ($raw !== null) {
return null;
}
return $this->quoter->quote('NULL', $depth);
}
}
@@ -0,0 +1,43 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function get_object_vars;
use function is_object;
use function sprintf;
final class ObjectStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier,
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_object($raw)) {
return null;
}
return $this->quoter->quote(
sprintf(
'[object] (%s: %s)',
$raw::class,
$this->stringifier->stringify(get_object_vars($raw), $depth + 1)
),
$depth
);
}
}
@@ -0,0 +1,41 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use function get_resource_type;
use function is_resource;
use function sprintf;
final class ResourceStringifier implements Stringifier
{
public function __construct(
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_resource($raw)) {
return null;
}
return $this->quoter->quote(
sprintf(
'[resource] (%s)',
get_resource_type($raw)
),
$depth
);
}
}
@@ -0,0 +1,37 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Stringifier;
use function is_object;
use function method_exists;
final class StringableObjectStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!is_object($raw)) {
return null;
}
if (!method_exists($raw, '__toString')) {
return null;
}
return $this->stringifier->stringify($raw->__toString(), $depth);
}
}
@@ -0,0 +1,60 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use Throwable;
use function getcwd;
use function sprintf;
use function str_replace;
final class ThrowableStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier,
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!$raw instanceof Throwable) {
return null;
}
return $this->quoter->quote(
sprintf(
'[throwable] (%s: %s)',
$raw::class,
$this->stringifier->stringify($this->getData($raw), $depth + 1)
),
$depth
);
}
/**
* @return mixed[]
*/
private function getData(Throwable $throwable): array
{
return [
'message' => $throwable->getMessage(),
'code' => $throwable->getCode(),
'file' => sprintf(
'%s:%d',
str_replace(getcwd() . '/', '', $throwable->getFile()),
$throwable->getLine()
),
];
}
}
@@ -0,0 +1,43 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier\Stringifiers;
use Respect\Stringifier\Quoter;
use Respect\Stringifier\Stringifier;
use Traversable;
use function iterator_to_array;
use function sprintf;
final class TraversableStringifier implements Stringifier
{
public function __construct(
private readonly Stringifier $stringifier,
private readonly Quoter $quoter
) {
}
public function stringify(mixed $raw, int $depth): ?string
{
if (!$raw instanceof Traversable) {
return null;
}
return $this->quoter->quote(
sprintf(
'[traversable] (%s: %s)',
$raw::class,
$this->stringifier->stringify(iterator_to_array($raw), $depth + 1)
),
$depth
);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of Respect/Stringifier.
* Copyright (c) Henrique Moody <henriquemoody@gmail.com>
* SPDX-License-Identifier: MIT
*/
declare(strict_types=1);
namespace Respect\Stringifier;
use Respect\Stringifier\Stringifiers\ClusterStringifier;
function stringify(mixed $value): string
{
static $stringifier;
if ($stringifier === null) {
$stringifier = ClusterStringifier::createDefault();
}
return $stringifier->stringify($value, 0) ?? '#ERROR#';
}