PHPackages                             theovdml/doh - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. theovdml/doh

ActiveLibrary

theovdml/doh
============

A flexible PHP error formated and stack trace formatter.

v1.0.2(10mo ago)2286[12 issues](https://github.com/theo-vdml/doh-php-error-formatter/issues)MITPHPPHP &gt;=8.1

Since Jun 16Pushed 10mo ago1 watchersCompare

[ Source](https://github.com/theo-vdml/doh-php-error-formatter)[ Packagist](https://packagist.org/packages/theovdml/doh)[ RSS](/packages/theovdml-doh/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (1)Versions (2)Used By (0)

 [![D'oh! PHP Throwable Formatter](./assets/hero.png)](./assets/hero.png)

D'oh! — PHP Throwable Formatter
===============================

[](#doh--php-throwable-formatter)

 [![Packagist Version](https://camo.githubusercontent.com/71dd5c638f405b4158bba3e76d02381a048423f4495b5f302e6c7eba7076aa07/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7468656f76646d6c2f646f68)](https://packagist.org/packages/theovdml/doh) [![GitHub Tag](https://camo.githubusercontent.com/626a2f8f36d027dd7d7c0bfc676f709dadd88c216d151a3b0cefc02750e12355/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f7468656f2d76646d6c2f646f682d7068702d6572726f722d666f726d6174746572)](https://github.com/theo-vdml/doh-php-error-formatter/releases) [![Total Downloads](https://camo.githubusercontent.com/04f64feebe22ff5ef3919d1618273819b905d089bc447c298bbc1c3f662994c0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7468656f76646d6c2f646f682e737667)](https://packagist.org/packages/theovdml/doh) [![License](https://camo.githubusercontent.com/cad20e9bd8fdd968d86fe14cb93fda5863e098d0b23e85d7428302de4ea9dd47/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7468656f76646d6c2f646f682e737667)](https://packagist.org/packages/theovdml/doh)

**D'oh!** is a lightweight, flexible PHP library for formatting exceptions and errors (`\Throwable`)
into various human- and machine-readable formats: HTML, JSON, JSON:API, plain text, and XML.

It simplifies transforming PHP exceptions into structured, beautifully formatted outputs,
perfect for error pages, API error responses, logs, or CLI tools.

Doh was originally designed as part of the Potager framework to provide elegant throwable formatting. However, it is fully decoupled and works perfectly as a standalone package in any PHP project. It’s not as ambitious or feature-rich as libraries like Whoops, and it’s still a work in progress with limited testing. Use with caution and feel free to contribute!

 **A delightful PHP Throwable formatter that says:**
 [![D'oh!](https://camo.githubusercontent.com/303ba3d3335b86faee1dc1df85dbfb7deb90c9bce5b07897ce779cd6ca41ae0d/68747470733a2f2f6d65646961332e67697068792e636f6d2f6d656469612f76312e59326c6b505463354d4749334e6a45784f544d78646e6777656d4532644735744e6d316e596d777a6233497863476c6d4d6a677962325a354f58566e63574934596e4a3064535a6c634431324d563970626e526c636d35686246396e61575a66596e6c666157516d593351395a772f385764734b36314439594f4f632f67697068792e676966)](https://camo.githubusercontent.com/303ba3d3335b86faee1dc1df85dbfb7deb90c9bce5b07897ce779cd6ca41ae0d/68747470733a2f2f6d65646961332e67697068792e636f6d2f6d656469612f76312e59326c6b505463354d4749334e6a45784f544d78646e6777656d4532644735744e6d316e596d777a6233497863476c6d4d6a677962325a354f58566e63574934596e4a3064535a6c634431324d563970626e526c636d35686246396e61575a66596e6c666157516d593351395a772f385764734b36314439594f4f632f67697068792e676966)

 *“D’oh!” — **Homer Simpson**, and now your error pages.*

Features
--------

[](#features)

✅ Elegant HTML output with syntax-highlighted source snippets
✅ Structured formats: JSON, JSON:API, Plain Text, and XML
✅ Standalone &amp; framework-agnostic — plug and play
✅ Composer-ready, PSR-4 autoloaded
✅ Ideal for APIs, CLIs, websites, and dev environments

Requirements
------------

[](#requirements)

- PHP 8.1 or higher
- Highlight.php 9.18 or higher

Installation
------------

[](#installation)

Install via Composer:

```
composer require theovdml/doh
```

Usage
-----

[](#usage)

```
use DohFormatting\Doh\Doh;

try {
    // Some code that throws an exception
    throw new RuntimeException("Something went wrong!");
} catch (\Throwable $e) {
    $formatter = new Doh($e);

    // Get HTML formatted error page (for web display)
    echo $formatter->toHtml();

    // Get JSON for API response or logging
    $json = $formatter->toJson();

    // Get JSON:API compliant error document
    $jsonApi = $formatter->toJsonApi();

    // Plain text (for CLI or logs)
    $text = $formatter->toPlainText();

    // XML error representation
    $xml = $formatter->toXml();
}
```

🧪 Example Output (HTML)
-----------------------

[](#-example-output-html)

Here’s what your exception looks like with `D'oh! → toHtml()`:

 [![HTML Exception Preview](./assets/html-preview.png)](./assets/html-preview.png)

> ✅ Clean layout, clear stack trace, highlighted code snippets — all wrapped in a developer-friendly interface.

API Documentation
-----------------

[](#api-documentation)

The core of **D'oh!** is the `Doh` class, which wraps a PHP `\Throwable` and provides flexible methods to format it into various output types. Below is a detailed overview of its API:

### `Doh::__construct(\Throwable $throwable)`

[](#doh__constructthrowable-throwable)

Creates a new formatter instance from a throwable (exception or error).

- **Parameters:**

    - `\Throwable $throwable` — The exception or error you want to format.
- **Usage:**

    ```
    $doh = new Doh($exception);
    ```

### `Doh::buildTrace(): Trace`

[](#dohbuildtrace-trace)

Generates a detailed `Trace` object representing the throwable's stack trace.

- This method:

    - Prepends a **virtual top frame** corresponding to the exact location where the throwable was thrown (file and line).
    - Compensates for PHP’s `Exception::getTrace()` behavior, which does not include the throw location itself.
    - Returns a `Trace` object containing an array of `Frame` objects, each representing a stack frame.
- **Returns:**`Trace` — an iterable collection of `Frame` objects representing the full stack trace, including the throw frame.
- **Usage example:**

    ```
    $trace = $doh->buildTrace();
    foreach ($trace as $frame) {
        echo $frame->getContext() . ' in ' . $frame->getFileLabel() . PHP_EOL;
    }
    ```

### `Doh::getThrowable(): \Throwable`

[](#dohgetthrowable-throwable)

Returns the original throwable instance wrapped by this formatter.

- **Returns:**`\Throwable`
- **Usage example:**

    ```
    $exception = $doh->getThrowable();
    ```

### `Doh::getClass(): string`

[](#dohgetclass-string)

Returns the fully qualified class name of the throwable.

- **Returns:**`string` — e.g. `"RuntimeException"`
- **Usage example:**

    ```
    echo $doh->getClass();  // Outputs: RuntimeException
    ```

### `Doh::getMessage(): string`

[](#dohgetmessage-string)

Returns the throwable's error message.

- **Returns:**`string`
- **Usage example:**

    ```
    echo $doh->getMessage();  // Outputs: Something went wrong!
    ```

Formatters
----------

[](#formatters)

Each formatter returns a string in a specific format representing the throwable and its trace.

### `Doh::toHtml(): string`

[](#dohtohtml-string)

- Produces a full **HTML error page** designed for developer-friendly display in browsers.
- Features:

    - Syntax-highlighted source code snippets around each frame.
    - Clear, styled stack trace.
    - File and line info with links or tooltips (if enabled).
- **Use case:** Custom error pages for web applications during development.

### `Doh::toJson(): string`

[](#dohtojson-string)

- Outputs a structured **JSON string** containing:

    - Throwable class, message, and code.
    - Full stack trace as an array of frames.
- **Use case:** API error responses or structured logging systems.

### `Doh::toJsonApi(): string`

[](#dohtojsonapi-string)

- Returns a **JSON:API-compliant** error document following [JSON:API specification](https://jsonapi.org/format/#errors).
- Includes:

    - Standardized keys like `status`, `code`, `title`, and detailed trace metadata.
- **Use case:** APIs adhering to JSON:API spec for error reporting.

### `Doh::toPlainText(): string`

[](#dohtoplaintext-string)

- Provides a **plain-text** formatted output of the error and its trace.
- Includes file, line, function, and message details.
- **Use case:** CLI tools, console logs, or environments without rich formatting.

### `Doh::toXml(): string`

[](#dohtoxml-string)

- Returns a **well-formed XML document** describing the throwable and its stack trace.
- Structure includes:

    - Root error element with code, message, file, and line.
    - Nested trace frames.
- **Use case:** Systems consuming XML error reports, legacy integrations, or logs requiring XML.

Advanced Usage: Working with `Trace` and `Frame`
------------------------------------------------

[](#advanced-usage-working-with-trace-and-frame)

While **D'oh!** is designed for straightforward formatting of exceptions, its core components — **Trace** and **Frame** — provide powerful abstractions for working with stack traces at a granular level. These classes let you analyze, filter, and manipulate error stack traces for custom logging, debugging, or error reporting.

### `DohFormatting\Doh\Exception\Trace`

[](#dohformattingdohexceptiontrace)

The `Trace` class represents the full stack trace of an exception, including a special *virtual frame* that points exactly to where the throwable was thrown. It acts as a container of `Frame` instances, each representing one step in the call stack.

#### Key Features and Methods

[](#key-features-and-methods)

- **Iterable Collection**Implements `IteratorAggregate`, so you can loop over all frames:

    ```
    foreach ($trace as $frame) {
        echo $frame->getContext() . PHP_EOL;
    }
    ```
- **Frame Access and Manipulation**

    - `append(Frame $frame)`: Add a frame at the end.
    - `prepend(Frame $frame)`: Add a frame at the beginning (used internally for the virtual throw frame).
    - `all()`: Get all frames as an array.
- **Filtering and Selection**

    - `mostRelevant()`: Returns the most relevant frame for debugging, prioritizing application code over vendor or internal frames.
    - `onlyApp()`: Returns only frames that originate from your app’s codebase (excludes vendor/internal frames).
- **Conversion Utilities**

    - `toArray()`: Converts all frames to an array of plain data, useful for custom serialization or further inspection.
    - `fromBacktrace(array $backtrace, array $virtualFrames = [])`: Static factory to create a `Trace` instance from a raw PHP debug backtrace plus optional virtual frames (like the throw site).

#### Example: Filtering for App Frames

[](#example-filtering-for-app-frames)

```
$trace = $doh->buildTrace();
$appFrames = $trace->onlyApp();

foreach ($appFrames as $frame) {
    echo $frame->getFileLabel() . ':' . $frame->line . ' - ' . $frame->getContext() . PHP_EOL;
}
```

### `DohFormatting\Doh\Exception\Frame`

[](#dohformattingdohexceptionframe)

Each `Frame` object represents one call in the stack trace with detailed information about the file, line, function, class, and call type.

#### Properties

[](#properties)

- `?string $file` — File path where the frame occurred.
- `?int $line` — Line number in the file.
- `string $function` — Function name (or special markers like `{main}`, `{closure}`).
- `string $class` — Class name if applicable.
- `string $type` — Call type: `->` for instance methods or `::` for static calls.
- `array $args` — Arguments passed to the function (can be useful for deeper inspection).

#### Useful Methods

[](#useful-methods)

- **Context and Location**

    - `getContext()`: Returns a human-readable string describing the call context, e.g. `"MyClass->myMethod()"` or `"myFunction()"`.
    - `getFileLabel()`: Returns the base filename or `"Core PHP/Internal Function"` if no file info is available.
    - `getFilePath()`: Full file path or empty string.
    - `getLineText()`: Returns a text snippet like `"at line 42"`.
- **Source Code Excerpts**

    - `getExcerpt(int $padding = 7)`: Returns a snippet of source code around the frame’s line (7 lines before and after by default). Returns `null` if the file is unavailable or unreadable. This is great for displaying context in error pages or logs.
- **Frame Classification**

    - `isInternal()`: True if the frame is an internal PHP function (no file info).
    - `isApp()`: True if the frame belongs to the application (non-vendor, non-internal).
    - `isVendor()`: True if the frame belongs to a vendor package (`/vendor/` in path).

#### Creating a Frame

[](#creating-a-frame)

Frames are usually created internally from backtrace arrays using:

```
$frame = Frame::fromArray([
    'file' => '/path/to/file.php',
    'line' => 123,
    'function' => 'myFunction',
    'class' => 'MyClass',
    'type' => '->',
    'args' => ['foo', 'bar'],
]);
```

#### Example: Displaying Frame Information

[](#example-displaying-frame-information)

```
foreach ($trace as $frame) {
    echo $frame->getFileLabel() . ':' . $frame->line . PHP_EOL;
    echo 'Called: ' . $frame->getContext() . PHP_EOL;
    echo $frame->getExcerpt(3) ?: '[No source available]' . PHP_EOL;
}
```

License
-------

[](#license)

MIT License © theo\_vdml

Contributing
------------

[](#contributing)

Feel free to submit issues or pull requests on GitHub. Please include tests and documentation for any new features.

Acknowledgments
---------------

[](#acknowledgments)

D’oh! uses [scrivo/highlight.php](https://github.com/scrivo/highlight.php) for source code syntax highlighting. Thanks to the open-source community for all the great tools.

###  Health Score

29

—

LowBetter than 60% of packages

Maintenance33

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

328d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/90734af9e380b0e97ae5c4e48912763026666776dfeb8b2feed0cd83a9019fd0?d=identicon)[theo\_vdml](/maintainers/theo_vdml)

---

Top Contributors

[![theo-vdml](https://avatars.githubusercontent.com/u/73583554?v=4)](https://github.com/theo-vdml "theo-vdml (6 commits)")

### Embed Badge

![Health badge](/badges/theovdml-doh/health.svg)

```
[![Health](https://phpackages.com/badges/theovdml-doh/health.svg)](https://phpackages.com/packages/theovdml-doh)
```

###  Alternatives

[ueberdosis/tiptap-php

A PHP package to work with Tiptap output

2599.2M34](/packages/ueberdosis-tiptap-php)[contao/core-bundle

Contao Open Source CMS

1231.6M2.3k](/packages/contao-core-bundle)[daux/daux.io

Documentation generator that uses a simple folder structure and Markdown files to create custom documentation on the fly

825191.0k1](/packages/daux-dauxio)[yiisoft/yii2-apidoc

API Documentation generator for the Yii framework 2.0

257701.8k31](/packages/yiisoft-yii2-apidoc)[spatie/commonmark-highlighter

Highlight your markdown code blocks with league/commonmark

138400.5k19](/packages/spatie-commonmark-highlighter)[sinnbeck/markdom

Converts markdown to html with classes

69122.6k2](/packages/sinnbeck-markdom)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
