PHPackages                             sapphirecat/lisp-signals - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. sapphirecat/lisp-signals

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

sapphirecat/lisp-signals
========================

Lisp-style signals, conditions, and restarts

v0.9.0(9y ago)011BSD-2-ClausePHPPHP ^5.6 || ^7.0

Since Aug 7Pushed 9y ago1 watchersCompare

[ Source](https://github.com/sapphirecat/lisp-signals)[ Packagist](https://packagist.org/packages/sapphirecat/lisp-signals)[ RSS](/packages/sapphirecat-lisp-signals/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependenciesVersions (2)Used By (0)

lisp-signals
============

[](#lisp-signals)

A signal/condition/restart system, inspired by Common Lisp and [Peter Seibel](http://gigamonkeys.com/book/).

What even?
==========

[](#what-even)

In most languages, PHP included, an exception is *thrown* at a low level and *caught* higher on the call stack. By the time it is caught, execution has left the lower levels, and there's no way to return to them.

In Common Lisp, the equivalent notions are that a signal is sent, and handled by a signal handler function. But, there's a third part, **restarts,** which can be registered at any level in between. The signal handler can choose any restart to invoke, and execution resumes *inside that function,* even if it's below the level of where the signal handler was registered.

The simplest example is implemented in the [appDoesNothing.php](./examples/appDoesNothing.php) example, using stuff defined in [common.inc.php](./examples/common.inc.php). All of the examples follow the log-parsing example in [Chapter 19](http://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html)of Practical Common Lisp.

I'm a lisper, how does it happen in PHP?
========================================

[](#im-a-lisper-how-does-it-happen-in-php)

Restarts are a special exception class that gets thrown, and declaring the restart is actually writing a try/catch block and telling the Signal class the restart exists. Low-level code calls *downward* into the signal-handling stuff to send errors or other conditions, so the stack stays intact.

I took another liberty with the Common Lisp design: signal names are actually the class name of a signal object that is sent. So an `error` is really a `Sapphirecat\Signal\Error` instance. This allows for signals to package however much data they want, and provide behavior for it, all in a single argument to the signal system (and handler functions.)

In this library, a signal handler is bound by `Signal::receive()`, signals are sent with `Signal::send()`, and active restarts are declared by `Signal::restart()`. The condition is a `SignalInterface` and a restart is actually invoked by throwing a `BaseRestart`.

The error and warning protocols are implemented in `Signal::error()` and `Signal::warning()` (with a `Silence` restart), respectively. Finally, the built-in `Error` condition can be subclassed, and sent with `Signal::sendError()`.

(I hope this terminology is accurate. I haven't gone deep into Lisp in a while.)

Installation
============

[](#installation)

Get it from composer:

```
composer require sapphirecat/lisp-signals "~0.9.0"

```

Alternatively, include the `autoload.php` in this repository's top level, and enjoy.

License
=======

[](#license)

2-clause BSD. If it breaks, you get to keep the pieces.

###  Health Score

22

—

LowBetter than 21% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity48

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

3610d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/01777025d58201f1e2bedf4a4293ee5c535cca646b7b1fe1aa11b2092768bfff?d=identicon)[sapphirecat](/maintainers/sapphirecat)

---

Top Contributors

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

### Embed Badge

![Health badge](/badges/sapphirecat-lisp-signals/health.svg)

```
[![Health](https://phpackages.com/badges/sapphirecat-lisp-signals/health.svg)](https://phpackages.com/packages/sapphirecat-lisp-signals)
```

###  Alternatives

[dcat-admin-extension/ueditor

百度在线编辑器

205.6k](/packages/dcat-admin-extension-ueditor)[kaystrobach/development-tools

111.9k](/packages/kaystrobach-development-tools)

PHPackages © 2026

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