PHPackages                             bunny/bunny - 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. [Queues &amp; Workers](/categories/queues)
4. /
5. bunny/bunny

ActiveLibrary[Queues &amp; Workers](/categories/queues)

bunny/bunny
===========

Performant pure-PHP AMQP (RabbitMQ) non-blocking ReactPHP library

v0.5.6(12mo ago)7426.5M↓20.1%107[32 issues](https://github.com/jakubkulhan/bunny/issues)[12 PRs](https://github.com/jakubkulhan/bunny/pulls)20MITPHPPHP ^7.1 || ^8.0CI passing

Since Mar 19Pushed 1mo ago35 watchersCompare

[ Source](https://github.com/jakubkulhan/bunny)[ Packagist](https://packagist.org/packages/bunny/bunny)[ RSS](/packages/bunny-bunny/feed)WikiDiscussions 0.6.x Synced 1mo ago

READMEChangelog (9)Dependencies (5)Versions (37)Used By (20)

BunnyPHP
========

[](#bunnyphp)

[![Continuous Integration](https://github.com/jakubkulhan/bunny/actions/workflows/ci.yml/badge.svg)](https://github.com/jakubkulhan/bunny/actions/workflows/ci.yml)[![Downloads this Month](https://camo.githubusercontent.com/7e906f73c7b61daefdb6debd84db6d631cfc2b176d7d1c9a61fc0c0791e2b3dd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f62756e6e792f62756e6e792e737667)](https://packagist.org/packages/bunny/bunny)[![Latest stable](https://camo.githubusercontent.com/bf910fed7930a4fa2450767c7e95d844c5c24f014454c68c44e8ad3a749fb145/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f62756e6e792f62756e6e792e737667)](https://packagist.org/packages/bunny/bunny)

> Performant pure-PHP AMQP (RabbitMQ) non-blocking ReactPHP library

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

[](#requirements)

BunnyPHP requires PHP 8.1 and newer.

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

[](#installation)

Add as [Composer](https://getcomposer.org/) dependency:

```
$ composer require bunny/bunny:@^0.6dev
```

Comparison
----------

[](#comparison)

You might ask if there isn't a library/extension to connect to AMQP broker (e.g. RabbitMQ) already. Yes, there are multiple options:

- [ext-amqp](http://pecl.php.net/package/amqp) - PHP extension
- [php-amqplib](https://github.com/php-amqplib/php-amqplib) - pure-PHP AMQP protocol implementation

Why should you want to choose BunnyPHP instead?

- You want **nice idiomatic PHP API** to work with (I'm looking at you, php-amqplib). BunnyPHP interface follows PHP's common **coding standards** and **naming conventions**. See tutorial.
- You **can't (don't want to) install PECL extension** that has latest stable version in 2014. BunnyPHP isn't as such marked as stable yet. But it is already being used in production.
- You have **both classic CLI/FPM and [ReactPHP](http://reactphp.org/)** applications and need to connect to RabbitMQ. BunnyPHP comes with an **asynchronous** client with a **synchronous** API using [`Fibers`](https://reactphp.org/async/).

Apart from that BunnyPHP is more performant than main competing library, php-amqplib. See [`benchmark/` directory](https://github.com/jakubkulhan/bunny/tree/master/benchmark)and [php-amqplib's `benchmark/`](https://github.com/videlalvaro/php-amqplib/tree/master/benchmark). (For `ext-amp`  is used.)

Benchmarks were run as:

```
$ php benchmark/producer.php N & php benchmark/consumer.php
```

LibraryN (# messages)Produce secProduce msg/secConsume secConsume msg/secphp-amqplib1000.0006711489980.00171458343ext-amqp1000.0003023310420.00891511217bunnyphp1000.0001945152710.000939106508bunnyphp +/-+345.8%/+155.6%+182.5%/+949.5%php-amqplib10000.0048272071670.01516665937ext-amqp10000.0023994168460.07837312760bunnyphp10000.0015976262020.01113989773bunnyphp +/-+302.2%/+150.2%+136.1%/+703.5%php-amqplib100000.0602041661020.14777267672ext-amqp100000.0227354398530.75480013249bunnyphp100000.0164416082320.10668593734bunnyphp +/-+366.1%/+138.2%+138.5%/+707.4%php-amqplib1000001.158033902761.47776267670ext-amqp1000000.9523191050077.49466513343bunnyphp1000000.8124301230881.07345493157bunnyphp +/-+136.3%/+117.2%+137.6%/+698.1%php-amqplib100000018.641325364418.99290252651ext-amqp100000012.868277771089.43213911182bunnyphp100000011.634218595311.94742683700bunnyphp +/-+160.2%/+110.6%+158.9%/+748.5%Quick Start
-----------

[](#quick-start)

### Producing

[](#producing)

```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->channel()->publish(
    body:       $message,     // The message you're publishing as a string
    routingKey: 'queue_name', // Routing key, in this example the queue's name
  );
  $bunny->disconnect();
}));

// Unlike the consumer example, we're not setting signal handlers before this a very quick operation
```

### Consuming

[](#consuming)

```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$consumerCleanUp = static function () {};
$bunny = new Client($configuration);
Loop::futureTick(async(static function () use (&$consumerCleanUp): void {
    $channel = $bunny->channel();
    $response = $channel->consume(
        async(static function (Message $message, Channel $channel, Client $bunny) {
            $success = handleMessage($message); // Handle your message here

            if ($success) {
                $channel->ack($message); // Acknowledge message
                return;
            }

            $channel->nack($message); // Mark message fail, message will be redelivered
        }),
        'queue_name',
    );
    $consumerCleanUp = static fn () => $channel->cancel($response->consumerTag);
}));

// Unlike the producer example, we do need signal handlers because this process can run for weeks and we want to shut down cleanly
$signals = [SIGINT, SIGTERM, SIGHUP];
$signalHandler = async(static function () use ($signals, &$signalHandler, &$consumerCleanUp, $bunny): void {
  foreach ($signals as $signal) {
      Loop::removeSignal($signal, $signalHandler);
  }

  $consumerCleanUp();
  $bunny->disconnect();
}))
foreach ($signals as $signal) {
    Loop::addSignal($signal, $signalHandler);
}
```

Always run moving parts in a fiber
----------------------------------

[](#always-run-moving-parts-in-a-fiber)

Since v0.6 Bunny has been rebuilt using [`Fibers`](https://reactphp.org/async/). This means that every method on `Client` and `Channel` must be called inside a fiber. In the examples this will be called using a `Loop::futureTick` call. In your applications this might be some other trigger like a HTTP request. As long as somewhere in the direct call stack this call is inside a fiber you'll be good.

All the examples from this point on will include a `Full Example` on how to use that specific example using a full connection cycle inside a fiber the example. For the above that would be the following, even tho it's not doing anything:

```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->connect();
}));
```

Tutorial
--------

[](#tutorial)

### Connecting

[](#connecting)

When instantiating the BunnyPHP `Client` accepts an array with connection options:

```
use Bunny\Client;
use Bunny\Configuration;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
$bunny->connect();
```

Using DSN```
use Bunny\Client;
use Bunny\Configuration;

$configuration = Configuration::fromDSN('amqp://USERNAME:PASSWORD@HOSTNAME/VHOST');

$bunny = new Client($configuration);
$bunny->connect();
```

### Connecting securely using TLS(/SSL)

[](#connecting-securely-using-tlsssl)

Options for TLS-connections should be specified as array `tls`:

```
use Bunny\Client;
use Bunny\Configuration;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
    tls:      [
        'cafile'      => 'ca.pem',
        'local_cert'  => 'client.cert',
        'local_pk'    => 'client.key',
    ],
);

$bunny = new Client($configuration);
$bunny->connect();
```

Using DSN```
use Bunny\Client;
use Bunny\Configuration;

$configuration = Configuration::fromDSN(
    'amqp://USERNAME:PASSWORD@HOSTNAME/VHOST?tls[cafile]=ca.pem&tls[local_cert]=client.cert&tls[local_pk]=client.key',
);

$bunny = new Client($configuration);
$bunny->connect();
```

For options description - please see [SSL context options](https://www.php.net/manual/en/context.ssl.php).

Note: invalid TLS configuration will cause connection failure.

See also [common configuration variants](examples/tls/).

### Providing client properties

[](#providing-client-properties)

Client Connections can [present their capabilities](https://www.rabbitmq.com/connections.html#capabilities) to a server by presenting an optional `client_properties` table when establishing a connection.

For example, a connection name may be provided by setting the [`connection_name` property](https://www.rabbitmq.com/connections.html#client-provided-names):

```
use Bunny\Client;
use Bunny\Configuration;

$configuration = new Configuration(
    host:             'HOSTNAME',
    vhost:            'VHOST',    // The default vhost is '/'
    user:             'USERNAME', // The default user is 'guest'
    password:         'PASSWORD', // The default password is 'guest'
    clientProperties: [
        'connection_name' => 'My connection',
    ],
);

$bunny = new Client($configuration);
$bunny->connect();
```

Obviously this can be dynamic, for example, on Kubernetes you can include the pod, the namespace, and any other environment variable in it:

```
use Bunny\Client;
use Bunny\Configuration;

$configuration = new Configuration(
    host:             'HOSTNAME',
    vhost:            'VHOST',    // The default vhost is '/'
    user:             'USERNAME', // The default user is 'guest'
    password:         'PASSWORD', // The default password is 'guest'
    clientProperties: [
        'connection_name' => 'Pod: ' . getenv('POD_NAME') . '; Release: ' . getenv('RELEASE_TAG') . '; Namespace: ' . getenv('POD_NAMESPACE'),
    ],
);

$bunny = new Client($configuration);
$bunny->connect();
```

### Publish a message

[](#publish-a-message)

Now that we have a connection with the server we need to create a channel and declare a queue to communicate over before we can publish a message, or subscribe to a queue for that matter.

```
$channel = $bunny->channel();
$channel->queueDeclare('queue_name'); // Queue name
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $channel->queueDeclare('queue_name'); // Queue name
  $channel->close(); // Not required as the Client::disconnect() method handles this for us if we don't, but added for completeness sake
  $bunny->disconnect();
}));
```

#### Publishing a message on a virtual host with quorum queues as a default

[](#publishing-a-message-on-a-virtual-host-with-quorum-queues-as-a-default)

From RabbitMQ 4 queues will be standard defined as Quorum queues, those are by default durable, in order to connect to them you should use the queue declare method as follows. In the current version of RabbitMQ 3.11.15 this is already supported, if the virtual host is configured to have a default type of Quorum.

```
$channel = $bunny->channel();
$channel->queueDeclare('queue_name', false, true); // Queue name
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $channel->queueDeclare('queue_name', false, true); // Queue name
  $channel->close(); // Not required as the Client::disconnect() method handles this for us if we don't, but added for completeness sake
  $bunny->disconnect();
}));
```

With a communication channel set up, we can now publish a message to the queue:

```
$channel->publish(
    $message,    // The message you're publishing as a string
    [],          // Any headers you want to add to the message
    '',          // Exchange name
    'queue_name', // Routing key, in this example the queue's name
);
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $channel->publish(
      $message,    // The message you're publishing as a string
      [],          // Any headers you want to add to the message
      '',          // Exchange name
      'queue_name', // Routing key, in this example the queue's name
  );
  $channel->close(); // Not required as the Client::disconnect() method handles this for us if we don't, but added for completeness sake
  $bunny->disconnect();
}));
```

Alternatively:

```
$channel->publish(
    body:       $message,     // The message you're publishing as a string
    routingKey: 'queue_name', // Routing key, in this example the queue's name
);
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $channel->publish(
      body:       $message,     // The message you're publishing as a string
      routingKey: 'queue_name', // Routing key, in this example the queue's name
  );
  $channel->close(); // Not required as the Client::disconnect() method handles this for us if we don't, but added for completeness sake
  $bunny->disconnect();
}));
```

### Subscribing to a queue

[](#subscribing-to-a-queue)

Subscribing to a queue can be done in two ways. The first way will run indefinitely:

```
$channel->consume(
    static function (Message $message, Channel $channel, Client $bunny) {
        $success = handleMessage($message); // Handle your message here

        if ($success) {
            $channel->ack($message); // Acknowledge message
            return;
        }

        $channel->nack($message); // Mark message fail, message will be redelivered
    },
    'queue_name',
);
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$consumerCleanUp = static function () {};
$bunny = new Client($configuration);
Loop::futureTick(async(static function () use (&$consumerCleanUp): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $response = $channel->consume(
      async(static function (Message $message, Channel $channel, Client $bunny) {
          $success = handleMessage($message); // Handle your message here

          if ($success) {
              $channel->ack($message); // Acknowledge message
              return;
          }

          $channel->nack($message); // Mark message fail, message will be redelivered
      }),
      'queue_name',
  );
  $consumerCleanUp = static fn () => $channel->cancel($response->consumerTag);
}));

$signals = [SIGINT, SIGTERM, SIGHUP];
$signalHandler = async(static function () use ($signals, &$signalHandler, &$consumerCleanUp, $bunny): void {
  foreach ($signals as $signal) {
      Loop::removeSignal($signal, $signalHandler);
  }

  $consumerCleanUp();
  $bunny->disconnect();
}))
foreach ($signals as $signal) {
    Loop::addSignal($signal, $signalHandler);
}
```

### Pop a single message from a queue

[](#pop-a-single-message-from-a-queue)

```
$message = $channel->get('queue_name');

// Handle message

$channel->ack($message); // Acknowledge message
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$bunny = new Client($configuration);
Loop::futureTick(async(static function (): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $message = $channel->get('queue_name');

  // Handle message

  $channel->ack($message); // Acknowledge message
  $channel->close(); // Not required as the Client::disconnect() method handles this for us if we don't, but added for completeness sake
  $bunny->disconnect();
}));
```

### Prefetch count

[](#prefetch-count)

A way to control how many messages are prefetched by BunnyPHP when consuming a queue is by using the channel's QOS method. In the example below only 5 messages will be prefetched. Combined with acknowledging messages this turns into an effective flow control for your applications, especially asynchronous applications. No new messages will be fetched unless one has been acknowledged.

```
$channel->qos(
    0, // Prefetch size
    5,  // Prefetch count
);
```

 Full Example```
use Bunny\Client;
use Bunny\Configuration;
use React\EventLoop\Loop;

use function React\Async\async;

$configuration = new Configuration(
    host:     'HOSTNAME',
    vhost:    'VHOST',    // The default vhost is '/'
    user:     'USERNAME', // The default user is 'guest'
    password: 'PASSWORD', // The default password is 'guest'
);

$consumerCleanUp = static function () {};
$bunny = new Client($configuration);
Loop::futureTick(async(static function () use (&$consumerCleanUp): void {
  $bunny->connect(); // Not required as the Client::channel() method handles this for us if we don't, but added for completeness sake
  $channel = $bunny->channel();
  $channel->qos(
      0, // Prefetch size
      5,  // Prefetch count
  );
  $response = $channel->consume(
      static function (Message $message, Channel $channel, Client $bunny) {
          $success = handleMessage($message); // Handle your message here

          if ($success) {
              $channel->ack($message); // Acknowledge message
              return;
          }

          $channel->nack($message); // Mark message fail, message will be redelivered
      },
      'queue_name',
  );
  $consumerCleanUp = static fn () => $channel->cancel($response->consumerTag);
}));

$signals = [SIGINT, SIGTERM, SIGHUP];
$signalHandler = async(static function () use ($signals, &$signalHandler, &$consumerCleanUp, $bunny): void {
  foreach ($signals as $signal) {
      Loop::removeSignal($signal, $signalHandler);
  }

  $consumerCleanUp();
  $bunny->disconnect();
}))
foreach ($signals as $signal) {
    Loop::addSignal($signal, $signalHandler);
}
```

### Asynchronous usage

[](#asynchronous-usage)

**Node: Up to version `v0.5.x` Bunny had two different clients, one sync, and one async. As of `v0.6` both clients have been folder into one: An async client with a sync API.**

AMQP interop
------------

[](#amqp-interop)

There is [amqp interop](https://github.com/queue-interop/amqp-interop) compatible wrapper(s) for the bunny library.

Testing
-------

[](#testing)

To fully test this package, TLS certificates are required and a local RabbitMQ. On top of that a Code Style fixer and Static Analysis are used in this project. To make it as simple as possible for anyone working on this project a `Makefile` is in place to take care of all of that.

```
$ make
```

Testing detailsCreate client/server TLS certificates by running:

```
$ cd test/tls && make all && cd -
```

You need access to a RabbitMQ instance in order to run the test suite. The easiest way is to use the provided Docker Compose setup to create an isolated environment, including a RabbitMQ container, to run the test suite in.

**Docker Compose**

- Use Docker Compose to create a network with a RabbitMQ container and a PHP container to run the tests in. The project directory will be mounted into the PHP container.

    ```
    $ docker-compose up -d
    ```

    To test against different TLS configurations (as in CI builds), you can set environment variable `CONFIG_NAME=rabbitmq.tls.verify_none` before running `docker-compose up`.
- Optionally use `docker ps` to display the running containers.

    ```
    $ docker ps --filter name=bunny
    [...] bunny_rabbit_node_1_1
    [...] bunny_bunny_1
    ```
- Enter the PHP container.

    ```
    $ docker exec -it bunny_bunny_1 bash
    ```
- Within the container, run:

    ```
    $ vendor/bin/phpunit
    ```

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

[](#contributing)

- Large part of the PHP code (almost everything in `Bunny\Protocol` namespace) is generated from spec in file [`spec/amqp-rabbitmq-0.9.1.json`](spec/amqp-rabbitmq-0.9.1.json). Look for `DO NOT EDIT!` in doc comments.

    To change generated files change [`spec/generate.php`](spec/generate.php) and run:

    ```
    $ php ./spec/generate.php
    ```

Broker compatibility
--------------------

[](#broker-compatibility)

Works well with RabbitMQ

Does not work with ActiveMQ because it requires AMQP 1.0 which is a completely different protocol (Bunny is implementing AMQP 0.9.1)

License
-------

[](#license)

BunnyPHP is licensed under MIT license. See `LICENSE` file.

###  Health Score

66

—

FairBetter than 99% of packages

Maintenance72

Regular maintenance activity

Popularity67

Solid adoption and visibility

Community46

Growing community involvement

Maturity70

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~154 days

Recently: every ~240 days

Total

27

Last Release

58d ago

PHP version history (4 changes)v0.1.0PHP &gt;=5.4.0

v0.3.0PHP ~7.0

v0.5.0PHP ^7.1 || ^8.0

v0.6.0-alpha.1PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/336ce4f2acf4ba19e86fe9edd33831c36d48e61858878d86af2b59728bf0a1a4?d=identicon)[jakubkulhan](/maintainers/jakubkulhan)

---

Top Contributors

[![WyriHaximus](https://avatars.githubusercontent.com/u/147145?v=4)](https://github.com/WyriHaximus "WyriHaximus (129 commits)")[![jakubkulhan](https://avatars.githubusercontent.com/u/95001?v=4)](https://github.com/jakubkulhan "jakubkulhan (55 commits)")[![mermshaus](https://avatars.githubusercontent.com/u/29676?v=4)](https://github.com/mermshaus "mermshaus (22 commits)")[![tomas-novotny](https://avatars.githubusercontent.com/u/36948723?v=4)](https://github.com/tomas-novotny "tomas-novotny (16 commits)")[![jeromegamez](https://avatars.githubusercontent.com/u/67554?v=4)](https://github.com/jeromegamez "jeromegamez (13 commits)")[![appkit-framework](https://avatars.githubusercontent.com/u/247590844?v=4)](https://github.com/appkit-framework "appkit-framework (9 commits)")[![standa](https://avatars.githubusercontent.com/u/163679?v=4)](https://github.com/standa "standa (5 commits)")[![kuai6](https://avatars.githubusercontent.com/u/9960215?v=4)](https://github.com/kuai6 "kuai6 (5 commits)")[![Tatikoma](https://avatars.githubusercontent.com/u/1888609?v=4)](https://github.com/Tatikoma "Tatikoma (4 commits)")[![simPod](https://avatars.githubusercontent.com/u/327717?v=4)](https://github.com/simPod "simPod (4 commits)")[![edudobay](https://avatars.githubusercontent.com/u/4432091?v=4)](https://github.com/edudobay "edudobay (3 commits)")[![fritz-gerneth](https://avatars.githubusercontent.com/u/1294731?v=4)](https://github.com/fritz-gerneth "fritz-gerneth (3 commits)")[![rtm-ctrlz](https://avatars.githubusercontent.com/u/4123596?v=4)](https://github.com/rtm-ctrlz "rtm-ctrlz (3 commits)")[![VincentLanglet](https://avatars.githubusercontent.com/u/9052536?v=4)](https://github.com/VincentLanglet "VincentLanglet (2 commits)")[![jsor](https://avatars.githubusercontent.com/u/55574?v=4)](https://github.com/jsor "jsor (2 commits)")[![kukulich](https://avatars.githubusercontent.com/u/260445?v=4)](https://github.com/kukulich "kukulich (1 commits)")[![besir](https://avatars.githubusercontent.com/u/2492578?v=4)](https://github.com/besir "besir (1 commits)")[![ceeram](https://avatars.githubusercontent.com/u/111448?v=4)](https://github.com/ceeram "ceeram (1 commits)")[![Donatello-za](https://avatars.githubusercontent.com/u/2649302?v=4)](https://github.com/Donatello-za "Donatello-za (1 commits)")[![enumag](https://avatars.githubusercontent.com/u/539462?v=4)](https://github.com/enumag "enumag (1 commits)")

---

Tags

amqpamqp-clientamqp0-9-1phpphp-libraryrabbitmqmessagereactphpqueuerabbitmqmessagingAMQPexchangereactrabbitqueueingbunnyreact-php

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[kdyby/rabbitmq

Integrates php-amqplib with RabbitMq and Nette Framework

30693.1k4](/packages/kdyby-rabbitmq)[php-amqplib/rabbitmq-bundle

Integrates php-amqplib with Symfony &amp; RabbitMq. Formerly emag-tech-labs/rabbitmq-bundle, oldsound/rabbitmq-bundle.

1.3k20.1M65](/packages/php-amqplib-rabbitmq-bundle)[enqueue/enqueue-bundle

Message Queue Bundle

27615.6M38](/packages/enqueue-enqueue-bundle)[enqueue/enqueue

Message Queue Library

19820.0M56](/packages/enqueue-enqueue)[pdezwart/php-amqp

PHP AMQP Binding Library

585242.0k2](/packages/pdezwart-php-amqp)[prolic/humus-amqp

PHP-AMQP library with RabbitMQ Extensions

76205.4k5](/packages/prolic-humus-amqp)

PHPackages © 2026

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