Remove Unnecessary PHP Composer Polyfills

Published On07 Apr 2020

A Polyfill is a package that provides functionality that could be missing in a given system. They seamlessly add the necessary functionality if it is not available already in your server environment.

One of the most popular polyfills we have in PHP/Composer world is symfony/polyfill-mbstring. Without any surprises, this package provides the functionality provided by the mbstring extension if it not already available on the server. At the time of writing, there are over 200 dependents for this package, and over whopping 177 million installations of it.

PHP mbstring extension is a popular extension that is available in pretty much every sane PHP setup, but package that require this polyfill makes all projects that have this polyfill require some minimal PHP code, even if you already have mbstring extension already enabled in its PHP setup. While PHP's opcache should help minimize the impact, this is still code that does not help if you have a fully compliant PHP environment.

Composer does not yet provide functionality that makes it possible for polyfill providers to specify if the package can be skipped if the PHP environment already has the necessary functionality.

This post is about a workaround that you can override and prevent the installation of polyfills if you are certain that the target server that the application runs on already has all the necessary functionality the polyfills are about to provide.

This has been discussed quite extensively in Composer, Symfony Polyfills, and even at Debian dependencies:

This is complicated because not every PHP application uses Composer at deployment, and the target server may need the polyfill although the dev environment fulfilled the polyfill functionality natively.

While working on a private project that I'm planning to deploy on a server that I have full control over, I was a bit annoyed to have Symfony polyfills automatically installed because another package that I have added as a dependency required the polyfill.

Composer replace option

Composer has a configuration directive called replace, that a package can declare a list of other packages it replaces. Composer will happily skip/remove the packages that are being replaced when you require the package. You can specify a list of polyfills that you wish to not install, in either the root composer.json file, or as a local package that in turn replaces the said package.

  "replace": {  
        "symfony/polyfill-ctype": "*",  
        "ralouphie/getallheaders": "*",  
        "symfony/polyfill-mbstring": "*",  
    }

The snippet above, when added to your root composer.json file will prevent the three mentioned packages from being installed. This will not check if the underlying functionality is already available, which you can ensure by requiring the necessary server environment from the same composer.json file.

    "require": {  
        "php": "^7.3",  
        "ext-mbstring": "*",  
        "ext-ctype": "*",  
    }

After adding the replace directives, make sure to run composer update, so composer can remove the packages if they are already installed.

If you would like to check the extensions installed in your PHP setup, run composer show --platform, and it will show all extensions and other information such as underlying libraries, thread-safety, etc that you can use in your composer.json file as replacements.

Replacements as a separate package

If putting multiple replace directives in your root composer.json file is not your thing, you can create a separate package with its own composer.json file that requires the extensions/versions and their counterpart replace packages. You do not have to publish this package to Packagist where composer local packages come handy:

    "repositories": [  
        {  
            "type": "path",  
            "url": "app/packages"  
        }  
    ],

Above snippet, when used in a root composer.json file, will tell composer to look for a package in the app/packages directory, where you can create a separate composer.json file that declares a new package with its own (and likely more strict) requirements for the platform and packages you'd like to skip polyfills for.

Recent Articles on PHP.Watch

All ArticlesFeed 
PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian

PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian

A guide for Debian and Ubuntu on how to install PHP 8.4 on a new server or how to upgrade an existing PHP setup to PHP 8.4.
How to fix `mysql_native_password` not loaded errors on MySQL 8.4

How to fix mysql_native_password not loaded errors on MySQL 8.4

How to fix the SQLSTATE[HY000] [1524] Plugin 'mysql_native_password' is not loaded errors caused in MySQL 8.4 no longer enabling the mysql_native_password plugin by default.
How to fix PHP Curl HTTPS Certificate Authority issues on Windows

How to fix PHP Curl HTTPS Certificate Authority issues on Windows

On Windows, HTTPS requests made with the Curl extension can fail because Curl has no root certificate list to validate the server certificates. This article discusses the secure and effective solutions, and highlights bad advice that can leave PHP applications insecure.
Subscribe to PHP.Watch newsletter for monthly updates

You will receive an email on last Wednesday of every month and on major PHP releases with new articles related to PHP, upcoming changes, new features and what's changing in the language. No marketing emails, no selling of your contacts, no click-tracking, and one-click instant unsubscribe from any email you receive.

Support PHP.Watch — If you find the articles, version information, Codex, and other PHP.Watch contributions useful, consider supporting through GitHub Sponsors. Your sponsorship helps dedicate more time to creating valuable content and improving the PHP community. Together, we can keep the momentum going — thank you for your support!

Thanks to the highest tier sponsor: @TomasVotruba for your generous support to keep PHP.Watch moving 💜