Browse Source

Added varExporter option to Handler, fixes #1

2.1.0 v1.0.2
Dustin Wilson 1 year ago
parent
commit
d1f0e70e4f
  1. 45
      README.md
  2. 3
      composer.json
  3. 158
      composer.lock
  4. 3
      lib/Catcher/HTMLHandler.php
  5. 10
      lib/Catcher/Handler.php
  6. 3
      lib/Catcher/PlainTextHandler.php

45
README.md

@ -2,6 +2,8 @@
[b]: https://github.com/Seldaek/monolog
[c]: https://github.com/symfony/yaml
[d]: https://www.php.net/manual/en/function.pcntl-fork.php
[e]: https://www.php.net/manual/en/function.print-r.php
[f]: https://github.com/symfony/var-exporter
# Catcher
@ -195,6 +197,7 @@ abstract class Handler {
protected bool $_outputToStderr = true;
protected bool $_silent = false;
protected string $_timeFormat = 'Y-m-d\TH:i:s.vO';
protected ?\Closure $varExporter = null;
public function __construct(array $options = []);
@ -244,7 +247,9 @@ _outputPrevious_: When true will output previous throwables. Defaults to _true_.
_outputTime_: When true will output times to the output. Defaults to _true_.
_outputToStderr_: When the SAPI is cli output errors to stderr. Defaults to _true_.
_silent_: When true the handler won't output anything. Defaults to _false_.
_timeFormat_: The PHP-standard date format which to use for times in output. Defaults to _"Y-m-d\\TH:i:s.vO"_.
_timeFormat_: The PHP-standard date format which to use for times in output. Defaults to _"Y-m-d\\TH:i:s.vO"_.
_varExporter_: A user-defined closure to use when printing arguments in backtraces. Defaults to _null_.
#### MensBeam\Foundation\Catcher\Handler::dispatch
@ -414,12 +419,48 @@ class YamlHandler extends Handler {
This theoretical class uses the [`symfony/yaml`][c] package in Composer and exposes a few of its options as options for the Handler. Using this class would be very similar to the examples provided at the beginning of this document:
```php
#!/usr/bin/env php
<?php
use MensBeam\Foundation\Catcher,
Your\Namespace\Goes\Here\YamlHandler;
require_once('vendor/autoload.php');
$catcher = new Catcher(new YamlHandler([
'outputNullAsTilde' => true
]);
```
More complex handlers are possible by extending the various methods documented above. Examples can be seen by looking at the code for both `HTMLHandler` and `PlainTextHandler`.
More complex handlers are possible by extending the various methods documented above. Examples can be seen by looking at the code for both `HTMLHandler` and `PlainTextHandler`.
## Setting a Custom Variable Exporter
By default internally [`print_r`][e] is used. This is due to tests made internally where it performed the best out of built-in options, including other functions which might otherwise be preferred. Starting in v1.0.2 `Handler`'s `varExporter` option allows for defining how arguments are printed in backtraces in Catcher. Here is an example:
```php
#!/usr/bin/env php
<?php
use MensBeam\Foundation\Catcher,
Symfony\Component\VarExporter\VarExporter;
use MensBeam\Foundation\Catcher\PlainTextHandler;
require_once('vendor/autoload.php');
$c = new Catcher(new PlainTextHandler([
'outputBacktrace' => true,
'varExporter' => fn(mixed $value): string|bool => VarExporter::export($value)
]));
throw new \Exception('Ook!');
```
Output:
```
[04:48:23] Exception: Ook! in file /home/mensbeam/super-awesome-project/ook.php on line 13
Stack trace:
1. Exception /home/mensbeam/super-awesome-project/ook.php:13
| [
| 'Ook!',
| ]
```
This example above uses the symfony/var-exporter package for a more modern human-readable variable export. However, using any variable printer is possible.

3
composer.json

@ -27,7 +27,6 @@
"mensbeam/html-dom": "^1.0",
"phpunit/phpunit": "^9.5",
"nikic/php-parser": "^4.15",
"eloquent/phony-phpunit": "^7.1",
"symfony/yaml": "^6.2"
"eloquent/phony-phpunit": "^7.1"
}
}

158
composer.lock

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dd7f0dc703d14f61f5c0d12d9106338f",
"content-hash": "73069560c4ea9f687930120ab8363d8f",
"packages": [
{
"name": "psr/log",
@ -2285,88 +2285,6 @@
],
"time": "2022-12-23T11:40:44+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.27.0",
@ -2450,80 +2368,6 @@
],
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/yaml",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3",
"reference": "6ed8243aa5f2cb5a57009f826b5e7fb3c4200cf3",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<5.4"
},
"require-dev": {
"symfony/console": "^5.4|^6.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"bin": [
"Resources/bin/yaml-lint"
],
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v6.2.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "theseer/tokenizer",
"version": "1.2.1",

3
lib/Catcher/HTMLHandler.php

@ -146,8 +146,9 @@ class HTMLHandler extends Handler {
$t->appendChild($this->_document->createTextNode(":{$frame['line']}"));
if (isset($frame['args'])) {
$varExporter = $this->_varExporter;
$pre = $this->_document->createElement('pre');
$pre->appendChild($this->_document->createTextNode(trim(print_r($frame['args'], true))));
$pre->appendChild($this->_document->createTextNode(trim($varExporter($frame['args']))));
$li->appendChild($pre);
}
}

10
lib/Catcher/Handler.php

@ -60,6 +60,12 @@ abstract class Handler {
protected bool $_silent = false;
/** The PHP-standard date format which to use for timestamps in output */
protected string $_timeFormat = 'Y-m-d\TH:i:s.vO';
/**
* A user-defined closure to use when printing arguments in backtraces
*
* @var ?(mixed): string|bool
*/
protected ?\Closure $_varExporter = null;
@ -73,6 +79,10 @@ abstract class Handler {
$this->$key = $value;
}
if ($this->_varExporter === null) {
$this->_varExporter = fn(mixed $value): string|bool => print_r($value, true);
}
}

3
lib/Catcher/PlainTextHandler.php

@ -127,7 +127,8 @@ class PlainTextHandler extends Handler {
);
if (!empty($frame['args']) && $this->_backtraceArgFrameLimit > $key) {
$output .= preg_replace('/^/m', "$indent| ", print_r($frame['args'], true)) . \PHP_EOL;
$varExporter = $this->_varExporter;
$output .= preg_replace('/^/m', "$indent| ", $varExporter($frame['args'])) . \PHP_EOL;
}
}

Loading…
Cancel
Save