PHPackages                             mcrumm/pecan - 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. [CLI &amp; Console](/categories/cli)
4. /
5. mcrumm/pecan

ActiveLibrary[CLI &amp; Console](/categories/cli)

mcrumm/pecan
============

An event-driven, non-blocking shell for ReactPHP based on the Symfony Console Shell.

v1.0(12y ago)43542MITPHPPHP &gt;= 5.4

Since Mar 24Pushed 11y ago2 watchersCompare

[ Source](https://github.com/mcrumm/pecan)[ Packagist](https://packagist.org/packages/mcrumm/pecan)[ RSS](/packages/mcrumm-pecan/feed)WikiDiscussions develop Synced 4d ago

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

Pecan
=====

[](#pecan)

Event-driven, non-blocking shell for [ReactPHP](http://reactphp.org).

Pecan (`/pɪˈkɑːn/`) provides a non-blocking alternative to the shell provided in the [Symfony Console](https://github.com/symfony/console) component. Additionally, Pecan includes a basic, framework-agnostic shell component called `Drupe` that can be used as the basis for building custom shells.

Shells
------

[](#shells)

### Drupe

[](#drupe)

`Pecan\Drupe` is a standalone component for building event-driven console components. I like to think of it as Pecan without the Shell.

Pass an `EventLoopInterface` to `start()` listening for input.

```
$loop  = \React\EventLoop\Factory::create();
$shell = new \Pecan\Drupe();

// $shell->start() returns $loop to allow this chaining.
$shell->start($loop)->run();

```

### Drupe Events

[](#drupe-events)

- `running` - The shell is running.
- `data` - Data was received from `STDIN`.
- `error` - Indicates an I/O problem.
- `close` - The shell was closed.

### Shell

[](#shell)

`Pecan\Shell` extends `Drupe` to provide an event-driven wrapper for a standard `Symfony\Component\Console\Application`. It can be used as a drop-in replacement for `Symfony\Component\Console\Shell`.

> **Note**: To maintain a Symfony Console-like workflow, calling `$shell->run()` on `Pecan\Shell` starts the EventLoop, so make sure it gets called last.

### Shell Events

[](#shell-events)

`Shell` emits the same events as `Drupe`.

Readline
--------

[](#readline)

`Pecan\Readline` provides an interface for reading line-by-line input from `STDIN`. This component is heavily inspired by, and strives for parity with the [NodeJS Readline Component](http://nodejs.org/api/readline.html).

### Readline Events

[](#readline-events)

- `line` - A line has been read from `STDIN`.
- `pause` - Reading from the stream has been paused.
- `resume` - Reading from the stream has resumed.
- `error` - The input stream encountered an error.
- `close` - Then input stream was closed.

Console
-------

[](#console)

`Pecan\Console\Console` provides a standard interface for working with `STDOUT` and `STDERR`. It is inspired heavily by the [NodeJS Console Component](http://nodejs.org/api/console.html) and takes some functionality from the [Symfony Console Component](http://symfony.com)

### Output

[](#output)

The Output classes extend the base Console Output. `StreamOutput` wraps a single stream resource, while `ConsoleOutput` contains both the `STDOUT` and `STDERR` streams.

- `StreamOutputInterface`
- `ConsoleOutputInterface`
- `PecanOutput`

Using Pecan
-----------

[](#using-pecan)

### Using Drupe as a Standalone Shell

[](#using-drupe-as-a-standalone-shell)

```
use Pecan\Drupe;

$loop   = \React\EventLoop\Factory::create();
$shell  = new Drupe();

// Example one-time callback to write the initial prompt.
// This resumes reading from STDIN and kicks off the shell.
$shell->once('running', function (Drupe $shell) {
    $shell->setPrompt('drupe> ')->prompt();
});

// Example callback for the data event.
// By convention, any call to write() will be followed by a call to prompt()
// once the data has been written to the output stream.
$shell->on('data', function ($line, Drupe $shell) {

    $command = (!$line && strlen($line) == 0) ? false : rtrim($line);

    if ('exit' === $command || false === $command) {
        $shell->close();
    } else {
        $shell->writeln(sprintf(PHP_EOL.'// in: %s', $line));
    }

});

// Example callback for the close event.
$shell->on('close', function ($code, Drupe $shell) {
    $shell->writeln([
        '// Goodbye.',
        sprintf('// Shell exits with code %d', $code),
    ]);
});

$shell->start($loop)->run();
```

### Using Shell with Symfony Console Applications

[](#using-shell-with-symfony-console-applications)

Here is a shell that echoes back any input it receives, and then exits.

```
// Pecan\Shell wraps a standard Console Application.
use Symfony\Component\Console\Application;
use Pecan\Shell;

$shell = new Shell(new Application('pecan'));

$shell->on('data', function($line, Shell $shell) {
    $shell->write($line)->then(function($shell) {
        $shell->close();
    });
});

$shell->run();
```

### Injecting An `EventLoopInterface` into `Pecan\Shell`

[](#injecting-an-eventloopinterface-into-pecanshell)

Unless you pass `\Pecan\Shell` an object implementing `EventLoopInterface` as its second constructor method, the `Shell` will get one from the EventLoop Factory. Keep this in mind if you want to integrate Pecan into an existing ReactPHP project.

```
use Symfony\Component\Console\Application;
use Pecan\Shell;

$loop  = \React\EventLoop\Factory::create();

// Do other things requiring $loop...

$shell = new Shell(new Application('pecan'), $loop);

// We must still let the shell run the EventLoop.
$shell->run();
```

### Example `exit` callback

[](#example-exit-callback)

```
// Example callback for the exit event.
$shell->on('exit', function($code, \Pecan\Shell $shell) {
    $shell->emit('output', [
        [
            'Goodbye.',
            sprintf('// Shell exits with code %d', $code)
        ],
        true
    ]);
});
```

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 87.5% 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

4436d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6ef52ce0a4d546c303cbf41b8003f68daed00f492bdb75e514cfba859df02621?d=identicon)[mcrumm](/maintainers/mcrumm)

---

Top Contributors

[![mcrumm](https://avatars.githubusercontent.com/u/168677?v=4)](https://github.com/mcrumm "mcrumm (7 commits)")[![scrutinizer-auto-fixer](https://avatars.githubusercontent.com/u/6253494?v=4)](https://github.com/scrutinizer-auto-fixer "scrutinizer-auto-fixer (1 commits)")

---

Tags

reactphpreadlinesymfony-console

### Embed Badge

![Health badge](/badges/mcrumm-pecan/health.svg)

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

###  Alternatives

[illuminate/console

The Illuminate Console package.

12944.1M5.1k](/packages/illuminate-console)[crazywhalecc/static-php-cli

Build single static PHP binary, with PHP project together, with popular extensions included.

1.8k13.9k](/packages/crazywhalecc-static-php-cli)[matthiasnoback/symfony-console-form

Use Symfony forms for Console command input

368264.8k8](/packages/matthiasnoback-symfony-console-form)[madewithlove/license-checker

CLI tool to verify allowed licenses for composer dependencies

54449.8k21](/packages/madewithlove-license-checker)[shel/neos-terminal

Neos CMS Ui terminal for running Eel expressions and other commands

1441.3k](/packages/shel-neos-terminal)

PHPackages © 2026

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