Welcome to Abdul Malik Ikhsan's Blog

Using conflict in composer.json for BC Break handling on Optional feature

Posted in hack, php by samsonasik on January 11, 2019

You may have a PHP library that can work with multiple project skeletons with optional feature, so the dependencies are not required. For example, your composer.json library looks like:

{
    "name": "your/library",
    "require": {
        "php": "^7.1",
    },
    "require-dev": {
        "foo/bar": "^2.0",
        "phpunit/phpunit": "^7.0"
    },
    "suggest": {
        "foo/bar": "^2.0 usage via Your\\Library\\Adapter\\Foo\\Bar adapter"
    }
}

The “foo/bar” library is an optional library which used in “your/library” that consume it, collected in the require-dev above for testing purpose.

The “foo/bar” library has class “Foo\Bar\Way”. There are 2 versions of “foo/bar” lib, which version 1 and version 2 have different signature as follow:

a. “foo/bar” version 1 of “Foo\Bar\Way”

namespace Foo\Bar;

class Way
{
    public function execute(string $a, string $b)
    {
        // ...
    }
}

b. “foo/bar” version 2 of “Foo\Bar\Way”

namespace Foo\Bar;

use stdClass;

class Way
{
    public function execute(stdClass $std)
    {
        // ...
    }
}

In above code, if current user are using foo/bar:^1.0, the user code will be break when user upgrade “your/library” to version 2.0. So, to avoid that, you can restrict it via “conflict”, as follow:

{
    "name": "your/library",
    "require": {
        "php": "^7.1",
    },
    "require-dev": {
        "foo/bar": "^2.0",
        "phpunit/phpunit": "^7.0"
    },
    "suggest": {
        "foo/bar": "^2.0 usage via Your\\Library\\Adapter\\Foo\\Bar adapter"
    },
    "conflict": {
        "foo/bar": "<2.0"
    }
}

Now, you can tag “your/library” as “2.0” and user won’t be allowed to install new tagged library if they still uses “foo/bar”:”^1.0″ in existing project, That’s it!