Table of Contents
Key Takeaways
PHP-HTTP and HTTPlug
Bootstrapping
Getting Started
The Plan
Prerequisites
Diffbot Class
API Abstract, Crawl and Search
Entity Factory
Entity Iterator
Tests
Conclusion
Frequently Asked Questions (FAQs) about PHP HTTP and HTTPlug
What is the difference between Guzzle5 and PHP HTTP/HTTPlug?
How do I migrate from Guzzle5 to PHP HTTP/HTTPlug?
What are the benefits of using PHP HTTP/HTTPlug over Guzzle5?
How do I install PHP HTTP/HTTPlug?
How do I use PHP HTTP/HTTPlug to send a request?
How do I handle responses with PHP HTTP/HTTPlug?
What is the purpose of the Discovery component in PHP HTTP/HTTPlug?
How do I use the Discovery component in PHP HTTP/HTTPlug?
What are the plugins in HTTPlug and how do I use them?
How do I handle errors in PHP HTTP/HTTPlug?
Home Backend Development PHP Tutorial Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug

Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug

Feb 16, 2025 am 10:04 AM

Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug

Key Takeaways

  • HTTPlug, a project by PHP-HTTP, allows for easy injection of any HTTP client into an SDK, providing a solution for applications that already have a preferred HTTP client in use and want to avoid using Guzzle.
  • The HTTPlug interface package and Guzzle 6 can be pulled in together using the composer require php-http/guzzle6-adapter command. This allows for the use of Guzzle 6 or any other adapter implementing HTTPlug’s HttpClient interface.
  • The PHP-HTTP project aims to have maximum support for all HTTP clients in PHP, including Guzzle 5 and 6, and Zend1 and 2. This allows for no conflicts with installed client versions and easy plugging in of the appropriate adapter.
  • The Diffbot SDK has been made PSR-7 compatible and receptive of other implementations of HTTP clients. It only needs an adapter that respects the HTTPlug interface for everything to work out of the box.
  • HTTPlug provides a new approach to abstracting HTTP client implementations in apps, offering extensibility for the cost of one additional layer of abstraction.

This article was peer reviewed by Márk Sági-Kazár and David Buchmann. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!


In a previous series, we built a PHP client for Diffbot. The client works well and is in relatively widespread use – we even tested it on a live app to make sure it’s up to par – but it depends heavily on Guzzle 5.

There are two problems with this:

  1. Guzzle 6 is out, and supports PSR 7. While the author of Guzzle claims Guzzle 5 will be supported for the foreseeable future, it’s safer to be skeptical of its longevity. Besides, while PSR 7 might have its quirks, it’s good to follow PSRs if only for the compatibility with other projects
  2. Someone implementing our client in their app might already have a preferred HTTP client in use, and would like to use theirs rather than Guzzle. We should allow for easy injection of any HTTP client into our SDK.

Coincidentally, there is a new project allowing us to do just that: HTTPlug.

Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug

Note: you don’t need to be familiar with the internal logic of the Diffbot SDK to follow along. The process in this article is applicable to any package with a concrete HTTP Client implementation and is easy to follow.

PHP-HTTP and HTTPlug

PHP-HTTP is a Github organization for HTTP related tools in PHP. It provides HTTPlug, a collection of interfaces and exceptions to define a minimal HTTP client contract on top of PSR-7 request and response. Implementations of this contract ​provide​ the virtual package php-http/client-implementation.

This means someone who uses Guzzle 6 can composer require php-http/guzzle6-adapter to pull in the adapter, the HTTPlug interface package, and Guzzle 6 itself as a dependency of the adapter.

HTTPlug is the entry point for a reusable package. It is the client abstraction all clients (like the Guzzle6 Adapter) are based on. These clients then further make use of their underlying packages / dependencies – Guzzle 6 in this case.

So, bottom to top:

  • an HTTP Client exists (Guzzle 6)
  • a Guzzle 6 adapter is built with HTTPlug as the interface for it, wraps Guzzle 6
  • an app needing to be able to make HTTP calls needs a client, requires HTTPlug’s HttpClient interface rather than Guzzle 6 directly
  • the app can then use Guzzle 6, or any other adapter implementing HTTPlug’s HttpClient interface and wrapping another third party HTTP Client

The team’s plan is to eventually have maximum support for all the various HTTP clients in PHP land: Guzzle 6, Guzzle 5, Zend2, Zend1, etc. That way, a user of a framework or app will have no conflicts with installed client versions, and will simply plug the appropriate adapter into the mix.

Note that we use the terms adapter and client here almost interchangeably – the adapters based on HTTPlug are both. They are wrappers around existing clients, but used directly as clients themselves.

Our plan in this post is to replace the concrete Guzzle 5 dependency of Diffbot’s PHP client with the HTTPlug version.

Note: HTTPlug and related packages are alpha software, and as such are subject to change. Converting anything to use them is a risky endeavor.

Bootstrapping

As usual, it’s recommended we use Homestead Improved to bootstrap our environment. Once we’re ready, we can clone and test the current stable version of the SDK:

git clone https://github.com/swader/diffbot-php-client
cd diffbot-php-client 
git checkout tags/0.4.5 
composer install
phpunit
Copy after login
Copy after login
Copy after login
Copy after login

The last command assumes PHPUnit is globally installed on the development environment.

All tests should pass (except for a skipped one that’s bugged and unfixable due to some nonsense), so we’re ready to begin the conversion.

Getting Started

First, we’ll need to create a new branch on which to develop this upgrade.

git checkout -b feature-httplug
Copy after login
Copy after login
Copy after login
Copy after login

Then, we add two dependencies into our composer.json file:

git clone https://github.com/swader/diffbot-php-client
cd diffbot-php-client 
git checkout tags/0.4.5 
composer install
phpunit
Copy after login
Copy after login
Copy after login
Copy after login

What this does is tell the client that from now on, it depends on a virtual package – this one. This means that in order to be used, the application using our Diffbot client (like this one) must select an implementation of this package (one of those listed at the link on Packagist). Of course, during development of the package, it would be impossible to test and see if everything’s working without an actual implementation, so we specify an additional require-dev dependency. In the specific case above, we use "php-http/guzzle6-adapter": "~0.2@dev". We chose that particular version simply because it’s the newest one and there’s no stable release.

Note: You may be wondering why we used the approach of adding values into composer.json rather than declaring dependencies interactively in the terminal like we usually do. This is because doing a composer require on a virtual package will throw an error – the package doesn’t really exist, it’s just its virtual name, a placeholder, so Composer will get confused not knowing what to install. There is an issue suggesting a change to this, but it’s not likely to happen soon.

Since the php-http packages are still under heavy development, we should add the following two values to our composer.json file:

git checkout -b feature-httplug
Copy after login
Copy after login
Copy after login
Copy after login

This is to allow the installation of dev packages (non-stable), but will prefer stable versions if they exist. So rather than fetch, say, PHPUnit 5.2.x which is highly unstable, it will fetch 5.0.8 (most up to date at the time of writing), but it will also succeed if we ask it for packages that don’t have stable releases (like the guzzle6-adapter).

We also need to remove the dependency on Guzzle5, if we intend to install Guzzle6. The final require blocks look like this:

	"require": {
        ...
        "php-http/client-implementation": "^1.0"
    },
    "require-dev": {
        ...
        "php-http/guzzle6-adapter": "~0.2@dev"
    },
Copy after login
Copy after login
Copy after login

The Plan

The way the SDK currently works is as follows: in the main Diffbot class, we optionally set an HTTPClient. This is currently bound to Guzzle’s implementation at version 5. If no custom client instance is set, the Diffbot class automatically uses a default client.

This client is then used by the Api Abstract’s call method to issue a get request to the given URL. Additionally, there is a custom call method in the Crawl API class and the Search API class.

The result of the call is saved as a $response, which is a Guzzle5 Response. That response is then additionally processed by the Entity Factory which checks its validity and builds entities from it, pushing them into Entity Iterator.

The plan is, thus, to:

  1. Replace Diffbot::setHttpClient with a method accepting an HTTPlug implementation
  2. Modify the API abstract’s, Crawl’s, and Search class’ call methods so that they can issue a GET request with any HTTP client implementation provided to them.
  3. Modify the Entity Factory and Entity Iterator so that they no longer depend on the Guzzle5 version of Response, but rather the PSR-7 counterpart.

The PHP-HTTP project has an additional package, Utils, which contains HttpMethodsClient. That class wraps a message factory and the HTTP client into one whole, making it easier to send requests with commonly used verbs like GET, POST, etc – thus translating into something similar to what we had so far: $client->get( ... ). What’s more, it also returns the PSR-7 ResponseInterface, which means the getBody method will be available to us – that’ll leave only the toJson method unimplemented, something we can easily do ourselves.

Additionally, the project has a Discovery component, which features some static classes for discovering installed factories and clients – this allows us to provide our end user with a zero-configuration experience in some cases (see docs).

With the battle plan laid out, we can get started with the refactoring.

Prerequisites

Let’s require the additional packages:

git clone https://github.com/swader/diffbot-php-client
cd diffbot-php-client 
git checkout tags/0.4.5 
composer install
phpunit
Copy after login
Copy after login
Copy after login
Copy after login

Diffbot Class

The Diffbot class has this line at the top:

git checkout -b feature-httplug
Copy after login
Copy after login
Copy after login
Copy after login

We can just change it to:

	"require": {
        ...
        "php-http/client-implementation": "^1.0"
    },
    "require-dev": {
        ...
        "php-http/guzzle6-adapter": "~0.2@dev"
    },
Copy after login
Copy after login
Copy after login

The setHttpClient method should flare up in the IDE now, saying it’s missing some required parameters, namely the client to use, and the message factory with which to build Request instances.

The method should be refactored into:

"prefer-stable": true,
"minimum-stability": "dev"
Copy after login
Copy after login

Alternatively, the Discovery classes can be imported with use statements at the top of the class.

This change has now allowed the end user of the Diffbot SDK to either:

  • have their own client installed and let the Discovery components in tandem with HttpMethodsClient take care of things automatically, or
  • configure their own HttpMethodsClient instance by injecting a custom instance of a PSR 7 Client and Message Factory into a new instance of it, and inject that into the setHttpClient method for full flexibility

Most users will use this on autopilot.

Next up, the call methods.

Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug

Because the HttpMethodsClient instance we implemented before has a get method, there are no changes needed in that regard. The $response instance, however, shows a mistmatch, and with good reason. The original $response expected by the EntityFactory is a Guzzle5 Response.

Due to the complaint being issued by EntityFactory, we don’t really need to edit the API Abstract – it’ll take care of things on its own. The Crawl class’ call counterpart is a bit different:

git clone https://github.com/swader/diffbot-php-client
cd diffbot-php-client 
git checkout tags/0.4.5 
composer install
phpunit
Copy after login
Copy after login
Copy after login
Copy after login

Two warnings here – the second line of the method which uses the json method of $response, and the EntityIterator instantiation which expects a Guzzle5 Response. The only line we can affect from here is the former, so let’s change it to:

git checkout -b feature-httplug
Copy after login
Copy after login
Copy after login
Copy after login

A similar change needs to be done in the Search class’ call method, where the line:

	"require": {
        ...
        "php-http/client-implementation": "^1.0"
    },
    "require-dev": {
        ...
        "php-http/guzzle6-adapter": "~0.2@dev"
    },
Copy after login
Copy after login
Copy after login

changes into:

"prefer-stable": true,
"minimum-stability": "dev"
Copy after login
Copy after login

Entity Factory

The EntityFactory class has the following import at the top:

    "require": {
        "php" : ">=5.4.0",
        "php-http/client-implementation": "^1.0"
    },
    "require-dev": {
        "symfony/var-dumper": "~2",
        "phpunit/phpunit": "^5.0",
        "php-http/guzzle6-adapter": "~0.2@dev"
    },
Copy after login

We can change this to:

composer require "php-http/utils" "php-http/discovery"
Copy after login

The same needs to be done in the EntityFactory interface which the EntityFactory class implements.

The other change is similar to what we did above, in the Crawl class. We change:

use GuzzleHttp\Client;
Copy after login

to

use Http\Client\Utils\HttpMethodsClient as Client;
Copy after login

in both checkResponseFormat and createAppropriateIterator methods.

Entity Iterator

We change:

<span>/**
</span><span> * Sets the client to be used for querying the API endpoints
</span><span> *
</span><span> * <span>@param Client $client
</span></span><span> * <span>@see http://php-http.readthedocs.org/en/latest/utils/#httpmethodsclient
</span></span><span> * <span>@return $this
</span></span><span> */
</span><span>public function setHttpClient(Client $client = null)
</span><span>{
</span>    <span>if ($client === null) {
</span>		<span>$client = new Client(
</span>		   <span><span>\Http\Discovery\HttpClientDiscovery</span>::find(),
</span>		   <span><span>\Http\Discovery\MessageFactoryDiscovery</span>::find()
</span>		<span>);
</span>    <span>}
</span>    <span>$this->client = $client;
</span>    <span>return $this;
</span><span>}
</span>
Copy after login

to

<span>public function call()
</span><span>{
</span>    <span>$response = $this->diffbot->getHttpClient()->get($this->buildUrl());
</span>
    <span>$array = $response->json();
</span>
    <span>if (isset($array['jobs'])) {
</span>        <span>$jobs = [];
</span>        <span>foreach ($array['jobs'] as $job) {
</span>            <span>$jobs[] = new JobCrawl($job);
</span>        <span>}
</span>
        <span>return new EntityIterator($jobs, $response);
</span>    <span>} elseif (!isset($array['jobs']) && isset($array['response'])) {
</span>        <span>return $array['response'];
</span>    <span>} else {
</span>        <span>throw new DiffbotException('It appears something went wrong.');
</span>    <span>}
</span><span>}
</span>
Copy after login

Tests

Mocking, the main way of testing HTTP requests and API calls, is different in Guzzle 6, so our tests need a slightly bigger overhaul.

As this tutorial is already a bit on the long side, please see the relevant feature branch if you’re interested in learning the differences in mocking between Guzzle 5 and Guzzle 6 and, specifically, between the two versions of the Diffbot SDK.

Finally, let’s run the tests:

$array = json_decode($response->getBody(), true);
Copy after login

Success! All passing (except the expected skipped test).

The Diffbot SDK is now not only PSR-7 compatible, but also receptive of other implementations of HTTP clients. All it needs is an adapter respecting the HTTPlug interface, and everything should work out of the box.

Conclusion

HTTPlug is a useful new approach to abstracting the HTTP client implementations in the apps we build. Whether we’re building HTTP clients ourselves or using them in other apps, PHP-HTTP provides a whole new world of extensibility for the reasonable price of one additional layer of abstraction.

If you’d like to help out by adding more adapter implementations, or just by trying the packages out and giving feedback, the team welcomes all contributions. Get in touch, or leave your feedback in the comments section below, and if you found this tutorial interesting, don’t forget to hit that like button!

Frequently Asked Questions (FAQs) about PHP HTTP and HTTPlug

What is the difference between Guzzle5 and PHP HTTP/HTTPlug?

Guzzle5 and PHP HTTP/HTTPlug are both HTTP clients used in PHP. Guzzle5 is a specific HTTP client, while PHP HTTP is an abstraction layer that allows you to use any HTTP client. HTTPlug is an extension of PHP HTTP that provides additional features. The main difference is that PHP HTTP and HTTPlug allow for more flexibility and interoperability, as they are not tied to a specific HTTP client.

How do I migrate from Guzzle5 to PHP HTTP/HTTPlug?

Migrating from Guzzle5 to PHP HTTP/HTTPlug involves replacing the Guzzle5 client with an adapter that implements the PHP HTTP interfaces. This can be done using the HTTPlug library, which provides adapters for various HTTP clients, including Guzzle5. Once the adapter is set up, you can use the PHP HTTP methods to send requests and handle responses.

What are the benefits of using PHP HTTP/HTTPlug over Guzzle5?

The main benefit of using PHP HTTP/HTTPlug over Guzzle5 is the increased flexibility and interoperability. With PHP HTTP/HTTPlug, you can switch between different HTTP clients without changing your code. This makes it easier to test your application with different clients and to switch clients if necessary. Additionally, HTTPlug provides a plugin system that allows you to add functionality to your HTTP client.

How do I install PHP HTTP/HTTPlug?

PHP HTTP/HTTPlug can be installed using Composer, a dependency management tool for PHP. You can install it by running the command composer require php-http/httplug. This will download the HTTPlug library and its dependencies.

How do I use PHP HTTP/HTTPlug to send a request?

To send a request with PHP HTTP/HTTPlug, you first need to create a request object. This can be done using the createRequest method of the MessageFactory interface. Once you have a request object, you can send it using the sendRequest method of the HttpClient interface.

How do I handle responses with PHP HTTP/HTTPlug?

Responses in PHP HTTP/HTTPlug are represented by the ResponseInterface interface. You can access the status code, headers, and body of the response using the getStatusCode, getHeaders, and getBody methods, respectively.

What is the purpose of the Discovery component in PHP HTTP/HTTPlug?

The Discovery component in PHP HTTP/HTTPlug is used to automatically find and use available HTTP adapters and message factories. This makes it easier to switch between different HTTP clients and to use the best available implementation.

How do I use the Discovery component in PHP HTTP/HTTPlug?

The Discovery component can be used by calling the static find method on the HttpClientDiscovery or MessageFactoryDiscovery classes. This will return an instance of the first available HTTP client or message factory.

What are the plugins in HTTPlug and how do I use them?

Plugins in HTTPlug are used to add functionality to the HTTP client. They can be used to add features like authentication, caching, and error handling. Plugins can be added to the client using the addPlugin method of the PluginClient class.

How do I handle errors in PHP HTTP/HTTPlug?

Errors in PHP HTTP/HTTPlug are represented by exceptions that implement the HttpClientException interface. You can catch these exceptions and handle them as needed. Additionally, you can use the ErrorPlugin to automatically convert non-200 responses into exceptions.

The above is the detailed content of Breaking Free from Guzzle5 with PHP-HTTP and HTTPlug. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

How does session hijacking work and how can you mitigate it in PHP? How does session hijacking work and how can you mitigate it in PHP? Apr 06, 2025 am 12:02 AM

Session hijacking can be achieved through the following steps: 1. Obtain the session ID, 2. Use the session ID, 3. Keep the session active. The methods to prevent session hijacking in PHP include: 1. Use the session_regenerate_id() function to regenerate the session ID, 2. Store session data through the database, 3. Ensure that all session data is transmitted through HTTPS.

Describe the SOLID principles and how they apply to PHP development. Describe the SOLID principles and how they apply to PHP development. Apr 03, 2025 am 12:04 AM

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

How to automatically set permissions of unixsocket after system restart? How to automatically set permissions of unixsocket after system restart? Mar 31, 2025 pm 11:54 PM

How to automatically set the permissions of unixsocket after the system restarts. Every time the system restarts, we need to execute the following command to modify the permissions of unixsocket: sudo...

How to debug CLI mode in PHPStorm? How to debug CLI mode in PHPStorm? Apr 01, 2025 pm 02:57 PM

How to debug CLI mode in PHPStorm? When developing with PHPStorm, sometimes we need to debug PHP in command line interface (CLI) mode...

Explain late static binding in PHP (static::). Explain late static binding in PHP (static::). Apr 03, 2025 am 12:04 AM

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

How to send a POST request containing JSON data using PHP's cURL library? How to send a POST request containing JSON data using PHP's cURL library? Apr 01, 2025 pm 03:12 PM

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...

See all articles