PHPackages                             symplely/hyper - 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. [HTTP &amp; Networking](/categories/http)
4. /
5. symplely/hyper

ActiveLibrary[HTTP &amp; Networking](/categories/http)

symplely/hyper
==============

An simple advance asynchronous PSR-7 and PSR-18 Http client using coroutines.

1.0.0(6y ago)64MITPHPPHP &gt;7.1CI failing

Since Sep 23Pushed 6y ago1 watchersCompare

[ Source](https://github.com/symplely/hyper)[ Packagist](https://packagist.org/packages/symplely/hyper)[ Docs](https://github.com/symplely/hyper)[ RSS](/packages/symplely-hyper/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (8)Dependencies (4)Versions (9)Used By (0)

hyper
=====

[](#hyper)

[![Build Status](https://camo.githubusercontent.com/d705c8a1bf3a2f46af245f5799f339d8b54423dda4c851724df77a0631fa98ec/68747470733a2f2f7472617669732d63692e6f72672f73796d706c656c792f68797065722e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/symplely/hyper)[![Build status](https://camo.githubusercontent.com/e26a03e58a378118ea01a529bdea05d1cce4981ac1d9516e3149b699293eb8ad/68747470733a2f2f63692e6170707665796f722e636f6d2f6170692f70726f6a656374732f7374617475732f306c3438756275616b6336777471716d2f6272616e63682f6d61737465723f7376673d74727565)](https://ci.appveyor.com/project/techno-express/hyper/branch/master)[![codecov](https://camo.githubusercontent.com/d51f752cc43eebbd6c35b7eb272f6f0677557583eb3db5a11dbba8e9c778b5e2/68747470733a2f2f636f6465636f762e696f2f67682f73796d706c656c792f68797065722f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/symplely/hyper)[![Codacy Badge](https://camo.githubusercontent.com/85ae2b6ea4e0facd82f61ec995797afe80b459f9d0681a2f7422162d327f32fc/68747470733a2f2f6170692e636f646163792e636f6d2f70726f6a6563742f62616467652f47726164652f6439303263336161303564373464663639396161396539363265373066363364)](https://www.codacy.com/app/techno-express/hyper?utm_source=github.com&utm_medium=referral&utm_content=symplely/hyper&utm_campaign=Badge_Grade)[![Maintainability](https://camo.githubusercontent.com/f8e57e924e6cf3bc67168cea7f790513837d33cd2e84a5b06b65ef11e51c951a/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f64623865653461646231343266666164333563392f6d61696e7461696e6162696c697479)](https://codeclimate.com/github/symplely/hyper/maintainability)

An simple advance PSR-7 implementation and asynchronous PSR-18 HTTP client using coroutines.

Table of Contents
-----------------

[](#table-of-contents)

- [Introduction/Usage](#introduction/usage)
- [Functions](#functions)
- [Installation](#installation)
- [Usage/Historical](#usage/historical)
- [Options](#options)
- [Contributing](#contributing)
- [License](#license)

Introduction/Usage
------------------

[](#introductionusage)

This package is based on [**coroutines**](https://symplely.github.io/coroutine/) using `yield` an `generator`, it requires our other repo package [Coroutine](https://github.com/symplely/coroutine). It's construction is inspired by and an overhaul of [shuttle](https://github.com/nimbly/shuttle), an PSR-18 client.

There is a lot to be said about *coroutines*, but for an quick overview, checkout this [video](https://youtu.be/NsQ2QIrQShU), if you have no formulary with the concept or construction. Only one thing to keep in mind when viewing the video, is that it's an overview of callbacks vs promises vs generators, an object given an async/await construction in other languages. And the `Promise` reference there, is referred here has as an `Task`, that returns a plain `Integer`.

This library and the whole *Coroutine* concept here, is base around *NEVER* having the user/developer *directly* accessing the *Task*, the *Promise* like object. For conceptually usage example see [Advanced Asyncio: Solving Real World Production Problems](https://youtu.be/yKfenooKl6M).

***From example's folder:***

```
/**
 * @see https://github.com/amphp/artax/blob/master/examples/6-parallel-requests.php
 */
include 'vendor/autoload.php';

use Async\Coroutine\Exceptions\Panicking;

// An infinite loop example task, this will output on all task executions, pauses, stalls, or whatever.
function lapse() {
    $i = 0;
    while(true) {
        $i++;
        print $i.'.lapse ';
        yield;
    }
}

// An initial function is required, this gives all other tasks an execution point to begin.
function main() {
    // start an background job/task
    yield \await(lapse());
    $uris = [
        "https://github.com/",
        "https://google.com/",
        "https://stackoverflow.com/",
        'http://creativecommons.org/'
    ];

    try {
        $uriId = [];

        // Make an asynchronous HTTP requests
        // this `array` will collect `int`, represents an `http task id`
        // each `request()` starts an new background task, does not block or wait.
        // the `array` will be passed to `fetch();` for resolution.
        foreach ($uris as $uri) {
            $uriId[] = yield \request(\http_get($uri));
        }

        // Executions here will pause and wait for each request to receive an response,
        // all previous tasks started will continue to run, so you will see output only
        // from the `lapse` task here until the foreach loop starts.
        // Doing `\fetchOptions(1);` before this statement will wait for only 1 response.
        $bodies = yield \fetch($uriId);

        foreach ($bodies as $id => $result) {
            $uri = \response_meta($result, 'uri');
            // will pause execution of loop until full body is received, only `lapse` task will still output
            $body = yield \response_body($result);
            print \EOL."HTTP Task $id: ". $uri. " - " . \strlen($body) . " bytes" . \EOL.\EOL;
        }
    } catch (Panicking $error) {
        echo 'There was a problem: '.$error->getMessage();
    }

    // display the collected stats logs
    \print_defaultLog();
    yield \http_closeLog();
    // if you don't the infinite loop will continue it's output.
    yield \shutdown();
}

// Coroutine code needs to be bootstrapped.
// The function called `MUST` have at least one `yield` statement.
\coroutine_run(\main());
```

Functions
---------

[](#functions)

The functions listed **here** and in **Core.php** file is the recommended way to use this package. An functional programming approach is being used, the actual OOP class library used is constantly changing, but these calling functions will not.

```
const SYMPLELY_USER_AGENT = 'Symplely Hyper PHP/' . \PHP_VERSION;

// Content types for header data.
const HTML_TYPE = 'text/html';
const OCTET_TYPE = 'application/octet-stream';
const XML_TYPE = 'application/xml';
const PLAIN_TYPE = 'text/plain';
const MULTI_TYPE = 'multipart/form-data';
const JSON_TYPE = 'application/json';
const FORM_TYPE = 'application/x-www-form-urlencoded';

/**
 * This function works similar to coroutine `await()`
 *
 * Takes an `request` instance or `yield`ed coroutine of an request.
 * Will immediately return an `int` HTTP task id, and continue to the next instruction.
 * Will resolve to an Response instance when `fetch()`
 *
 * - This function needs to be prefixed with `yield`
 */
yield \request();

/**
 * Run awaitable HTTP tasks in the requests set concurrently and block
 * until the condition specified by count.
 *
 * This function works similar to `gatherWait()`.
 *
 * Controls how the `wait/fetch` functions operates.
 * `await()` will behave like **Promise** functions `All`, `Some`, `Any` in JavaScript.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \fetch_await($requests, $count, $exception, $clearAborted);

/**
 * This function works similar to coroutine `gather()`
 *
 * Takes an array of request HTTP task id's.
 * Will pause current task and continue other tasks until
 * the supplied request HTTP task id's resolve to an response instance.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \fetch(...$requests);

/**
 * This function works similar to `cancel_task()`
 *
 * Will abort the supplied request HTTP task id and close stream.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \request_abort($httpId);

/**
 * This function is automatically called by the http_* functions.
 *
 * Creates and returns an `Hyper` instance for the global HTTP functions by.
 */
\http_instance($tag);

/**
 * Clear & Close the global `Hyper`, and `Stream` Instances by.
 */
\http_clear($tag);

/**
 * Close and Clear `ALL` global Hyper function, Stream instances.
 */
\http_nuke();

/**
 * Make a GET request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_get($tagUri, ...$authorizeHeaderOptions);

/**
 * Make a PUT request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_put($tagUri, ...$authorizeHeaderOptions);

/**
 * Make a POST request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_post($tagUri, ...$authorizeHeaderOptions);

/**
 * Make a PATCH request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_patch($tagUri, ...$authorizeHeaderOptions);

/**
 * Make a DELETE request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_delete($tagUri, ...$authorizeHeaderOptions);

/**
 * Make a OPTIONS request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_options($tagUri, ...$authorizeHeaderOptions);

/**
 * Make a HEAD request, will pause current task, and
 * continue other tasks until an response is received.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \http_head($tagUri, ...$authorizeHeaderOptions);

/**
 * This function is automatically called by the http_* functions.
 *
 * Set global functions response instance by.
 */
\response_set($response, $tag);

/**
 * This function is automatically called by the response_* functions.
 *
 * Return current global functions response instance by.
 */
\response_instance($tag);

/**
 * Clear and close global functions response/stream instance by.
 */
\response_clear($tag);

/**
 * Close and Clear `ALL` global functions response instances.
 */
\response_nuke();

/**
 * Is response from an successful request?
 * Returns an `bool` or NULL, if not ready.
 *
 * This function can be used in an loop control statement,
 * which you will `yield` on `NULL`.
 */
\response_ok($tag);

/**
 * Returns response reason phrase `string` or NULL, if not ready.
 *
 * This function can be used in an loop control statement,
 * which you will `yield` on `NULL`.
 */
\response_phrase($tag);

/**
 * Returns response status code `int` or NULL, if not ready.
 *
 * This function can be used in an loop control statement,
 * which you will `yield` on `NULL`.
 */
\response_code($tag);

/**
 * Check if response has header key by.
 * Returns `bool` or NULL, if not ready.
 *
 * This function can be used in an loop control statement,
 * which you will `yield` on `NULL`.
 */
\response_has($tag, $header);

/**
 * Retrieve a response value for header key by.
 * Returns `string` or NULL, if not ready.
 *
 * This function can be used in an loop control statement,
 * which you will `yield` on `NULL`.
 */
\response_header($tag, $header);

/**
 * returns response FULL body.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \response_body($tag);

/**
 * Returns `string` of response metadata by key.
 */
\response_meta($tag, $key);

/**
 * Check if response body been read completely by.
 * Returns `bool` or NULL, if not ready.
 *
 * This function can be used in an loop control statement,
 * which you will `yield` on `NULL`.
 */
\response_eof($tag);

/**
 * returns response STREAM body.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \response_stream($tag, $size);

/**
 * returns response JSON body.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \response_json($tag, $assoc);

/**
 * returns response XML body.
 *
 * - This function needs to be prefixed with `yield`
 */
yield \response_xml($tag, $assoc);
```

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

[](#installation)

```
composer require symplely/hyper

```

Usage/Historical
----------------

[](#usagehistorical)

***Making requests: The easy old fashion way, with one caveat, need to be prefix with yield***

The quickest and easiest way to begin making requests is to use the HTTP method name:

```
use Async\Request\Hyper;

function main() {
    $http = new Hyper;

    $response = yield $http->get("https://www.google.com");
    $response = yield $http->post("https://example.com/search", ["Form data"]));
```

This library has built-in methods to support the major HTTP verbs: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, and `OPTIONS`. However, you can make **any** HTTP verb request using the **request** method directly, that returns an *PSR-7* `RequestInterface`.

```
    $request = $http->request("connect", "https://api.example.com/v1/books");
    $response = yield $http->sendRequest($request);
```

***Handling responses***

Responses in *Hyper* implement *PSR-7* `ResponseInterface` and as such are streamable resources.

```
    $response = $http->get("https://api.example.com/v1/books");

    echo $response->getStatusCode(); // 200
    echo $response->getReasonPhrase(); // OK

    // The body is return asynchronous in an non-blocking mode,
    // and as such needs to be prefixed with `yield`
    $body = yield $response->getBody()->getContents();
}

// All coroutines/async/await needs to be enclosed/bootstrapped
// in one `main` entrance routine function to properly execute.
// The function `MUST` have at least one `yield` statement.
\coroutine_run(\main());
```

***Handling failed requests***

This library will throw a `RequestException` by default if the request failed. This includes things like host name not found, connection timeouts, etc.

Responses with HTTP 4xx or 5xx status codes *will not* throw an exception and must be handled properly within your business logic.

***Making requests: The PSR-7 way, with one caveat, need to be prefix with yield***

If code reusability and portability is your thing, future proof your code by making requests the PSR-7 way. Remember, PSR-7 stipulates that Request and Response messages be immutable.

```
use Async\Request\Uri;
use Async\Request\Request;
use Async\Request\Hyper;

function main() {
    // Build Request message.
    $request = new Request;
    $request = $request
        ->withMethod("get")
        ->withUri(Uri::create("https://www.google.com"))
        ->withHeader("Accept-Language", "en_US");

    $http = new Hyper;
    // Send the Request.
    // Pauses current/task and send request,
    // will continue next to instruction once response is received,
    // other tasks/code continues to run.
    $response = yield $http->sendRequest($request);
}

// All coroutines/async/await needs to be enclosed/bootstrapped
// in one `main` entrance routine function to properly execute.
// The function `MUST` have at least one `yield` statement.
\coroutine_run(\main());
```

### Options

[](#options)

The following options can be pass on each request.

```
$http->request($method, $url, $body = null, array ...$authorizeHeaderOptions);
```

- `Authorization` An array with *key* as either: `auth_basic`, `auth_bearer`, `auth_digest`, and *value* as `password` or `token`.
- `Headers` An array of key &amp; value pairs to pass in with each request.
- `Options` An array of key &amp; value pairs to pass in with each request.

***Request bodies***

An easy way to submit data with your request is to use the `Body` class. This class will automatically transform the data, convert to a **BufferStream**, and set a default **Content-Type** header on the request.

Pass one of the following **CONSTANTS**, onto the class constructor will:

- `Body::JSON` Convert an associative array into JSON, sets `Content-Type` header to `application/json`.
- `Body::FORM` Convert an associative array into a query string, sets `Content-Type` header to `application/x-www-form-urlencoded`.
- `Body::XML` Does no conversion of data, sets `Content-Type` header to `application/xml`.
- `Body::FILE` Does no conversion of data, will detect and set `Content-Type` header.
- `Body::MULTI` Does no conversion of data, sets `Content-Type` header to `multipart/form-data`.

To submit a JSON payload with a request:

```
use Async\Request\Body;
use Async\Request\Hyper;

function main() {
    $book = [
        "title" => "Breakfast Of Champions",
        "author" => "Kurt Vonnegut",
    ];

    $http = new Hyper;

    yield $http->post("https://api.example.com/v1/books", [Body::JSON, $book]);
    // Or
    yield $http->post("https://api.example.com/v1/books", new Body(Body::JSON, $book));
    // Or
    yield $http->post("https://api.example.com/v1/books", Body::create(Body::JSON, $book));

    // Otherwise the default, will be submitted in FORM format of `application/x-www-form-urlencoded`
    yield $http->post("https://api.example.com/v1/books", $book);
}

// All coroutines/async/await needs to be enclosed/bootstrapped
// in one `main` entrance routine function to properly execute.
// The function `MUST` have at least one `yield` statement.
\coroutine_run(\main());
```

### Contributing

[](#contributing)

Contributions are encouraged and welcome; I am always happy to get feedback or pull requests on Github :) Create [Github Issues](https://github.com/symplely/hyper/issues) for bugs and new features and comment on the ones you are interested in.

### License

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity8

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity58

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

Every ~24 days

Recently: every ~30 days

Total

8

Last Release

2252d ago

Major Versions

0.9.9beta7 → 1.0.02020-03-09

### Community

Maintainers

![](https://www.gravatar.com/avatar/b1a9d88c23f07f785e0358746ae2384950a6f8dac0c3bd4fbbc910e94f7eb637?d=identicon)[techno-express](/maintainers/techno-express)

---

Top Contributors

[![TheTechsTech](https://avatars.githubusercontent.com/u/29784725?v=4)](https://github.com/TheTechsTech "TheTechsTech (133 commits)")

---

Tags

asynchronouscoroutineshttp-clientphppsr-18psr-7requestresponsiveyieldhttprequestpsr-7messageasyncclientpsr-18generatorcoroutineyieldawait

###  Code Quality

TestsPHPUnit

### Embed Badge

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

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

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.0B3.1k](/packages/guzzlehttp-psr7)[psr/http-factory

PSR-17: Common interfaces for PSR-7 HTTP message factories

1.9k692.9M1.9k](/packages/psr-http-factory)[react/http

Event-driven, streaming HTTP client and server implementation for ReactPHP

78126.4M414](/packages/react-http)[swow/swow

Coroutine-based multi-platform support engine with a focus on concurrent I/O

1.3k2.1M84](/packages/swow-swow)[chillerlan/php-httpinterface

A PSR-7/17/18 http message/client implementation

1417.1k5](/packages/chillerlan-php-httpinterface)[vultr/vultr-php

The Official Vultr API PHP Wrapper.

2243.9k1](/packages/vultr-vultr-php)

PHPackages © 2026

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