PHPackages                             wickedbyte/tombstone - 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. [Testing &amp; Quality](/categories/testing)
4. /
5. wickedbyte/tombstone

ActiveLibrary[Testing &amp; Quality](/categories/testing)

wickedbyte/tombstone
====================

Basic implementation of the Tombstone pattern for PHP to uncover zombie code

v1.1.1(6mo ago)25MITPHPPHP 8.2.\* || 8.3.\* || 8.4.\* || 8.5.\*CI passing

Since Apr 22Pushed 6mo agoCompare

[ Source](https://github.com/wickedbyte/tombstone)[ Packagist](https://packagist.org/packages/wickedbyte/tombstone)[ RSS](/packages/wickedbyte-tombstone/feed)WikiDiscussions main Synced today

READMEChangelog (4)Dependencies (12)Versions (5)Used By (0)

Tombstone
=========

[](#tombstone)

This library includes a variety of ways handling tombstone hits in your codebase, including handlers that trigger PHP errors (e.g. `E_USER_DEPRECATED`), use the local filesystem to track tombstone hits, and drop-in integrations for your project's existing PSR-3 Logger, PSR-14 Event Dispatcher, PSR-6/PSR-16 Cache implementations.

Installation &amp; Configuration
--------------------------------

[](#installation--configuration)

Install as a non-development dependency with Composer:

```
composer require wickedbyte/tombstone
```

Somewhere in your project's bootstrap process or service container (e.g. via a service provider), configure a new `GraveyardConfiguration` instance, and pass it to the `Graveyard::config()` method. For example:

```
    use WickedByte\Tombstone\Graveyard;
    use WickedByte\Tombstone\GraveyardConfiguration;

    Graveyard::config(new GraveyardConfiguration(handlers: [
        new \WickedByte\Tombstone\Handlers\InMemoryRateLimitHandler(),
        new \WickedByte\Tombstone\Handlers\PhpErrorHandler(),
        // Add additional handlers for your project here...
    ]));
```

If, for some reason, a tombstone is hit before the configuration is set, the library will default to a fallback configuration that will log the tombstone hit as a PHP `E_USER_DEPRECATED` error.

The `GraveyardConfiguration` class accepts the following named arguments:

- `rethrow_exceptions`: A boolean indicating whether exceptions that occur while handling the `TombstoneActivated` event should be rethrown or suppressed. This can be useful for debugging, but should be disabled in production. The default is `false`.
- `trace_depth`: The number of stack frames to include in the tombstone's backtrace. This can be used to reduce the size of the tombstone log output. The default is `10`. Setting the value to `0` will use the full backtrace stack trace.
- `logger`: A optional PSR-3 logger instance that will be used to for logging exceptions that occur while handling the `TombstoneActivated` event as errors. Note: this logger is separate from the logger used by the PSR-3 tombstone handlers, though you can certainly pass the same `LoggerInterface` instance to both.
- `handlers`: An array of `TombstoneHandlerInterface` instances that will be called when a tombstone is hit. The handlers will be called in the order they are defined in the array. If a handler sets the `TombstoneActivated`instance's `$propagate` property to `false`, no further handlers will be invoked. This can be used to prevent spamming logs or other side effects. The defaults are `InMemoryRateLimitHandler` and `PhpErrorHandler`.

Usage
-----

[](#usage)

To mark a location in your code as a tombstone, use the `tombstone` function:

```
    \tombstone('2021-01-01 This code is *probably* dead');
```

Alternatively, you can use the `Graveyard::tombstone()` static method directly:

```
    \WickedByte\Tombstone\Graveyard::tombstone('2021-01-01 This code is *probably* dead');
```

Both methods accept an arbitrary string message argument. The message should be brief, and may include a date or other information about when or why the code tombstone was added. The message will be logged when the tombstone is hit, and is used as part of the tombstone's unique identifier. This means that if you can add more granularity by making the message string dynamic.

The second parameter, `$extra`, is an optional array of additional context information that can be used by your custom helper implementations. For example, if you add a handler that sends an email notification, you can use the `$extra` array to include the email address of the person who added the tombstone and the recipient address.

Tombstone Handlers
------------------

[](#tombstone-handlers)

### Included Tombstone Handlers

[](#included-tombstone-handlers)

#### `InMemoryRateLimitHandler`

[](#inmemoryratelimithandler)

While code that is assumed to already be dead will *probably* not be hit frequently, it's better to be safe than sorry, especially when paying for production log storage.

To reduce spamming logs and other side effects when a tombstone is hit in a loop or at high-frequency, this handler will limit the number of tombstone hits that are logged to one-per-request. More accurately -- important for non-HTTP contexts, like queue workers and cron-jobs -- one-per-instantiation of the configured handler class. The underlying array is a key/value pairing of the tombstone's 8-byte identifier and the value `true`, in order to minimize memory usage.

#### `PhpErrorHandler`

[](#phperrorhandler)

This handler will trigger a PHP error when a tombstone is hit, allowing your project's error handling system to log the tombstone hit as it would any other PHP error. By default, the error level is `E_USER_DEPRECATED`, but the other three runtime user error levels (`E_USER_ERROR`, `E_USER_WARNING` and `E_USER_NOTICE`) are also supported.

#### `FilesystemGraveyardHandler`

[](#filesystemgraveyardhandler)

This handler uses the local filesystem to track tombstone hits. Provide it with a directory path (it can create the directory if it does not exist) and tombstone activations will be logged to a file in that directory, one per tombstone ID. You will need to manually clear the directory if you want to reset the tombstone. We only touch the file if it does not already exist.

#### `PsrLoggerHandler`

[](#psrloggerhandler)

This handler will log tombstone hits to a PSR-3 logger instance, e.g. Monolog. The default log level is `warning`, but can be configured with any of the PSR-3 log levels. The handler will log additional context information about the tombstone hit, including the tombstone's message, the stack trace, and contextual information for the current request.

#### `PsrEventDispatcherHandler`

[](#psreventdispatcherhandler)

This handler integrates with your existing PSR-14 Event Dispatcher, and dispatches the `TombstoneActivated` event. This allows you to add additional listeners to the event, that do not have to implement the `TombstoneHandlerInterface` interface, and are defined along with the rest of your project's event listeners.

#### `PsrCacheHandler` / `PsrSimpleCacheHandler`

[](#psrcachehandler--psrsimplecachehandler)

These handlers will cache tombstone hits using a PSR-6 or PSR-16 cache instance. If the cache implementation uses some kind of remote driver like Redis or Memcached, this can be useful for tracking tombstone hits across multiple servers or processes. The cache key is the tombstone's unique identifier, and the value is either the `TombstoneActivated` instance or `1`. The latter is much more memory and bandwidth efficient, but does not include the tombstone's message or stack trace, which might be useful for debugging, just how a tombstone was hit, and by whom.

The default cache TTL is `86400` seconds (24 hours), but can be configured to any non-negative integer value. If the TTL is set to `0`, the cache will never expire -- you probably do not want that, though it is technically allowed.

### Creating Custom Tombstone Handlers

[](#creating-custom-tombstone-handlers)

To create a custom handler, implement the `TombstoneHandlerInterface` interface:

```
    use WickedByte\Tombstone\TombstoneActivated;

    interface TombstoneHandlerInterface
    {
        public function handle(TombstoneActivated $tombstone): void;
    }
```

Then add an instance of your custom handler to the `GraveyardConfiguration` instance. Handlers can be dynamically added or reset at runtime by calling the `Graveyard::config()->pushHandlers()` or `Graveyard::config()->setHandlers()` methods.

If you want to stop the propagation of the tombstone event to other handlers, set the `$propagate` property of the passed in `TombstoneActivated` instance to `false`.

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

[](#contributing)

Run `make` to build the project Docker image, create the "./build" cache directory and install vendor dependencies with Composer.

To upgrade the project dependencies to their current major versions, run `make upgrade`, or to just update them within the bounds of their currently defined constraints, run `make update`

Common Actions with Makefile targets:

- `make bash`
- `make phpunit`
- `make psysh`
- `make phpcs`
- `make phpstan`
- `make rector`
- `make rector-dry-run`
- `make ci`

To get a fresh start, run `make clean` to delete the vendor and build directories, which will trigger a docker image rebuild, the next time `make` is run.

For anything else not defined in the Makefile, use:

```
docker compose run --rm -it app {your-command-here}
```

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance66

Regular maintenance activity

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity62

Established project with proven stability

 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

Every ~199 days

Total

4

Last Release

204d ago

PHP version history (2 changes)1.0.0PHP 8.2.\* || 8.3.\*

v1.1.0PHP 8.2.\* || 8.3.\* || 8.4.\* || 8.5.\*

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7006523?v=4)[Andy Snell](/maintainers/andysnell)[@andysnell](https://github.com/andysnell)

---

Top Contributors

[![andysnell](https://avatars.githubusercontent.com/u/7006523?v=4)](https://github.com/andysnell "andysnell (13 commits)")

---

Tags

refactoringdead codecode qualitytombstonezombie code

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Type Coverage Yes

### Embed Badge

![Health badge](/badges/wickedbyte-tombstone/health.svg)

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

###  Alternatives

[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M571](/packages/shopware-core)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[laravel/framework

The Laravel Framework.

34.8k543.8M20.0k](/packages/laravel-framework)[symfony/cache

Provides extended PSR-6, PSR-16 (and tags) implementations

4.2k373.5M3.3k](/packages/symfony-cache)[symfony/mailer

Helps sending emails

1.6k409.1M1.4k](/packages/symfony-mailer)

PHPackages © 2026

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