Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
/ecs.php export-ignore
/rector.php export-ignore
/tests export-ignore
/benchmarks export-ignore
7 changes: 1 addition & 6 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,5 @@ jobs:
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Execute tests with mutation
if: ${{ matrix.os == 'ubuntu-latest' && matrix.php == '8.5' }}
run: vendor/bin/pest --colors=always --mutate --parallel --min=50

- name: Execute tests
if: ${{ matrix.os != 'ubuntu-latest' || matrix.php != '8.5' }}
run: vendor/bin/pest --colors=always
run: vendor/bin/pest --colors=always --parallel
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,28 @@ $data = json_repair_decode(
);
```

## Logging

The library supports PSR-3 logging for debugging repair operations. Pass any PSR-3 compatible logger to see what repairs are being made:

```php
use Psr\Log\LoggerInterface;

// Using the helper function
$repaired = json_repair($broken, logger: $logger);

// Using the class (implements LoggerAwareInterface)
$repairer = new JsonRepairer($broken);
$repairer->setLogger($logger);
$repaired = $repairer->repair();
```

Log messages include the position in the JSON string and a context snippet showing where the repair occurred. This is useful for:

- Debugging why certain repairs are being made
- Understanding how malformed JSON is being interpreted
- Tracking repair operations in production environments

## Credits

- [Sean Tymon](https://github.com/tymondesigns)
Expand Down
22 changes: 20 additions & 2 deletions benchmarks/JsonRepairerBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

/**
* @Revs(100)
* @Iterations(20)
* @Iterations(10)
* @Warmup(2)
*/
class JsonRepairerBench
Expand Down Expand Up @@ -41,7 +41,15 @@ public function benchRepairValidJson(array $params): void
}

/**
* Benchmarks large JSON repair.
*
* Note: This benchmark uses fewer revs/iterations since it processes
* 1000 items and takes ~44ms per run. Use --filter=benchRepairLargeJson
* to run it separately.
*
* @ParamProviders({"provideLargeJson"})
* @Revs(10)
* @Iterations(5)
*/
public function benchRepairLargeJson(array $params): void
{
Expand Down Expand Up @@ -81,6 +89,16 @@ public function benchRepairStreamingJson(array $params): void
json_repair($params['json']);
}

/**
* Baseline: compare repair overhead against native json_decode on valid JSON.
*
* @ParamProviders({"provideValidJson"})
*/
public function benchNativeJsonDecodeBaseline(array $params): void
{
json_decode($params['json']);
}

/**
* @return array<string, array<string, string>>
*/
Expand Down Expand Up @@ -141,7 +159,7 @@ public function provideLargeJson(): array
$brokenJson = rtrim($brokenJson, '}') . ',}';

return [
'large_array' => ['json' => $brokenJson],
'large_array_broken' => ['json' => $brokenJson],
];
}

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
],
"require": {
"php": "^8.3",
"ext-json": "*"
"ext-json": "*",
"psr/log": "^3.0"
},
"require-dev": {
"colinodell/psr-testlogger": "^1.3",
"pestphp/pest": "^4.1.4",
"pestphp/pest-plugin-type-coverage": "^4.0.3",
"phpbench/phpbench": "^1.4",
Expand Down
10 changes: 8 additions & 2 deletions phpbench.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
"$schema": "https://raw.githubusercontent.com/phpbench/phpbench/master/lib/phpbench.schema.json",
"runner.bootstrap": "vendor/autoload.php",
"runner.path": "benchmarks",
"runner.iterations": 20,
"runner.iterations": 10,
"runner.revs": 100,
"runner.warmup": 2,
"runner.time_unit": "microseconds"
"runner.time_unit": "microseconds",
"report.generators": {
"compare": {
"generator": "table",
"cols": ["benchmark", "subject", "set", "revs", "its", "mem_peak", "mode", "rstdev"]
}
}
}
30 changes: 30 additions & 0 deletions src/Exceptions/JsonRepairException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Cortex\JsonRepair\Exceptions;

use RuntimeException;

class JsonRepairException extends RuntimeException
{
/**
* Create a new exception for invalid JSON after repair.
*
* This exception is thrown when the repair process completes but the
* resulting output is still not valid JSON.
*
* @param string $json The repaired JSON that is still invalid
*
* @return self A new JsonRepairException instance
*/
public static function invalidJsonAfterRepair(string $json): self
{
return new self(
sprintf(
'JSON repair completed but the result is still invalid JSON: %s',
$json,
),
);
}
}
Loading