📜 ⬆️ ⬇️

Optional dependencies are not needed.

In this post we will discuss PHP packages and used alcohol dependencies. Rather, the so-called optional or proposed dependencies (optional dependencies, suggest / dev-dependencies), which are defined in composer.json.

What is addiction?


To begin with, let’s deal with what dependence is and what it is all about. There is the following code:

namespace Gaufrette\Adapter; use Gaufrette\Adapter; use \MongoGridFS; class GridFS implements Adapter { private $gridFS; public function __construct(MongoGridFS $gridFS) { $this->gridFS = $gridFS; } public function read($key) { $file = $this->find($key); return ($file) ? $file->getBytes() : false; } } 

The GridFS class is part of the Gaufrette abstract filesystem library , which I have changed to some extent. To determine all dependencies of this piece of code, we must ask ourselves the following questions:
')


But you need to think about this:

  1. What version of PHP will you need to run to get no errors?
  2. Perhaps you will need to install some specific version?
  3. What PHP extensions will be needed?
  4. What PEAR libraries do I need to install?
  5. What packages are missing?

Returning to the GridFS class, the PHP version must be at least 5.3, because neimspaces are used. Also, the class \MongoGridFS , which is a mongo extension to PHP and is available only from version 0.9.0 of this extension. Everything seems to create composer.json:

 { ..., "require": { "php": ">=5.3", "ext-mongo": ">=0.9.0" } .. } 

This list is enough and now it seems like nothing stops us from using this class in our applications ... Alas, this is not so.

Valid list of dependencies knplabs / gaufrette


As I said before, GridFS is part of the Gaufrette library, which provides an abstract file system layer for storing files on various types of file systems without worrying about the details of the file system used. Take a look at the composer.json of this library:

 { "name": "knplabs/gaufrette", "require": { "php": ">=5.3.2" }, "require-dev": { ... }, "suggest": { ... "amazonwebservices/aws-sdk-for-php": "to use the legacy Amazon S3 adapters", "phpseclib/phpseclib": "to use the SFTP", "doctrine/dbal": "to use the Doctrine DBAL adapter", "microsoft/windowsazure": "to use Microsoft Azure Blob Storage adapter", "ext-zip": "to use the Zip adapter", "ext-apc": "to use the APC adapter", "ext-curl": "*", "ext-mbstring": "*", "ext-mongo": "*", "ext-fileinfo": "*" }, ... } 

And here he is, the first surprise! Almost everything that turned out about dependencies earlier is no good, because the library says that it just needs PHP version not lower than 5.3.2, and everything else - to your taste, optionally or only for dev purposes - call it what you want .

Of course, people who have been using Composer or Packagist for a long time have become accustomed to such things. But this is just the wrong approach. As we found out earlier, ext-mongo is a true dependency of the GridFS class, but composer.json tells us the opposite.

All this means is that if we want to use this class in our project, it is not enough just to use the knplabs/gaufrette . I also made ext-mongo necessary in my project, which is a mistake: it is not my project that requires the mongo extension, but the knplabs/gaufrette . Moreover, how can I find out which version of ext-mongo to choose? Those dependencies that are listed in the suggest block do not talk about it, forcing me to choose.

It's just another package.


knplabs/gaufrette not the only one who acts in this way, presenting real dependencies as suggested. It is convenient for package owners to add different classes that users may need. Or not needed. Therefore, if the use of these classes is optional, then their dependencies are also optional. However, package owners forget that dependencies are never optional. They are always required, because the code simply does not work without them.

Decision


What should package developers do in this case? Separate them. In the case of knplabs/gaufrette this means that there must be a knplabs/gaufrette package containing all the common code needed to abstract from the file system. And then each individual adapter, such as the GridFS, should live in its package, for example, knplabs/gaufrette-mongo-gridfs . And he will already have his dependencies:

 { ..., "require": { "php": ">=5.3", "knplabs/gaufrette": "~0.1" "ext-mongo": ">=0.9.0" } } 

And everything, nowhere there are hidden dependencies, they are all necessary.

The knplabs/gaufrette in turn, no longer has dependencies at all, and the packages with adapters are just proposed:

 { "require": { "php": ">=5.3.2" }, "suggested": { "knplabs/gaufrette-mongo-gridfs": "For storing files using Mongo GridFS", ... } } 

This approach has a number of advantages:


Next time, adding the proposed dependencies to your package, think about whether it is a valid dependency in this package? Then split the package and specify this dependency in it as necessary. If all the code in the main package works without this proposed dependency, then it can be specified as suggested.

Source: https://habr.com/ru/post/219837/


All Articles