9

Organizing PHP Quality Tools

In the last two chapters, you learned a lot about quality metrics and how to measure them. There will surely be a couple of tools you would like to use in your future work environment, and these tools work best if they are seamlessly integrated so that you don’t even have to think about using them anymore.

Therefore, in this chapter, we will show you how you can organize these tools in a way that they will be the most productive and helpful in your daily work. This includes the following topics:

  • Installing code quality tools using Composer
  • Installing code quality tools as phar files
  • Managing phar files using the PHAR Installation and Verification Environment (Phive)

Technical requirements

If you followed the examples in the previous two chapters, you do not need to install anything else. If not, please go back to those chapters and install all the necessary tools first.

All code samples can be found in our GitHub repository: https://github.com/PacktPublishing/Clean-Code-in-PHP.

Installing code quality tools using Composer

Most PHP: Hypertext Preprocessor (PHP) projects nowadays use Composer for a good reason. Before it entered the PHP world in 2012, keeping all external dependencies (that is, code from other developers) up to date required a lot of manual work. The required files had to be downloaded from the corresponding websites and added to the correct folders of the project. Autoloading (that is, the automatic resolving of file paths from the class name) was not standardized, if available at all. So, usually, the wanted classes needed to be actively imported using require() or require_once(). If there were any conflicts between package versions, you had to somehow solve the issues yourself.

Composer greatly simplified these efforts by solving these issues. It introduced a central repository called Packagist (https://packagist.org), where all available packages are hosted. Furthermore, it fixed the version problem by introducing version constraints. These are rules that tell Composer which versions of other packages a package supports, enabling Composer to often automatically resolve the right versions. Another groundbreaking feature was the support of autoloading for installed packages. There, we now usually use require() only to import Composer’s autoloader.

All these features helped PHP compete with other web languages such as Python or Ruby, and without it, PHP would probably not be the most widely used language on the World Wide Web (WWW) anymore, as it is today. Therefore, we want to give Composer the space in this book that it deserves. In this section, we will show you the most used installation method. Additionally, we will also have a look at another, lesser-known way of using Composer in your project.

Installing code quality tools using require-dev

Throughout the last chapters, we already used Composer to install tools most of the time, so by now, you should already be familiar with the most common use case there is: adding dependencies to your project. Dependencies are code packages written by other developers that can quickly be integrated into your project.

To recap, this is done using the require keyword and the package name. For example, if you want to add PhpMetrics, you can do so by running the following command:

$ composer require phpmetrics/phpmetrics --dev

Typically, packages are identified by the name of the developer(s)—the so-called vendor—and, separated by a slash, the package name. In the preceding example, the vendor and the package name are identical, but this is not always the case.

Let us look at the --dev option in more detail now. When we run the composer require command with this option, Composer will add the package in another section of the composer.json file, called require-dev. Here, you can see an excerpt of a typical composer.json file:

{
  "name": "vendor/package",
  ...
  "require": {
    "doctrine/dbal": "^2.10",
    "monolog/monolog": "^2.2",
    ...
  },
  "require-dev": {
    "phpunit/phpunit": "^9.5",
    "phpmetrics/phpmetrics": "^2.8",
    ...
  },
  ...
}

The idea behind the require-dev section is that all packages within this section are not necessary to run the application in production. In the local environment, or during the build, you will surely need PHPUnit and all our held-dear code quality tools; in production, they are not needed anymore, though.

In fact, you should strive to have as few packages as possible in production. This is mainly for two reasons, as follows:

  1. Each package you add will be included in Composer’s autoload mechanism, which costs performance on every request. Internally, Composer builds a so-called classmap, which is a simple array that maps a class name to the respective file location. If you are curious about this, check out—for example—the vendor/composer/autoload_classmap.php file. Depending on the number of packages your project uses, this file can get huge, slowing down your application.
  2. Every additional package can possibly introduce security issues. The less code there is, the fewer attack vectors there are.

By default, Composer will install all dependencies. Thus, be sure to run it using the --no-dev option for your production builds to exclude the packages in require-dev from being installed. In your local environment, however, you do not need to worry about anything else at this point.

The previously described installation method is the one you will encounter the most for good reasons: it does not require any additional tooling and there’s just one additional option to be used when installing it on production. This makes it a perfect starting point and is often fully sufficient for a small project. Another approach worth knowing is the global installation of Composer, which we will discuss in the next section.

Global installation

If you are working on numerous projects simultaneously on your local system, you can choose to install Composer and packages globally, which means that they will not be installed in any project root folder and will thus not be added to any composer.json file there. Instead, both Composer and the packages will be installed in a single folder, which is usually ~/.composer. In this folder, you will then find another composer.json file that keeps track of the globally installed packages, as well as another vendor folder, where their code is installed.

Installing packages globally simply requires adding the global modifier, like so:

$ composer global require phpmetrics/phpmetrics

Likewise, updating all global packages is effortless too, as demonstrated here:

$ composer global update

After global installation, tools such as the PHP Coding Standards Fixer (PHP-CS-Fixer) can simply be executed without having to specify the path, like so:

$ php-cs-fixer fix src

To make this approach work, however, you will need to add this global folder to the execution path. Please see the Composer documentation (https://getcomposer.org/) for more details on how to do this for the operating system you use.

Using the global installation feature should only be chosen if you are working alone on your projects and do not use any build pipelines. If you are working in a team and/or make use of a continuous integration (CI) pipeline, you should install it for every project separately, though.

According to common best practices such as the Twelve-Factor App principles (https://12factor.net), all dependencies should be explicitly declared, and no global dependencies should be relied on since you can never be sure which version will be installed. Although code quality tool packages are not part of the actual program code, they are still part of the build process. Even small differences between the installed versions can lead to unforeseen behavior and can generate confusion when errors cannot be reproduced locally.

Furthermore, you want to make the initial installation of a project as easy as possible. Having your teammates install all the required tools manually is a time-wasting and error-prone process that can lead to frustration.

For the aforementioned reasons, we do not encourage using the global installation method.

Composer scripts

Once you have decided on a possible way to install Composer and have used it to download your desired tools, you want to start using them in the most straightforward way possible. In Chapter 11, Continuous Integration, where we will talk about CI, we will also show you how to run these tools automatically during the build process. For now, however, we want to show you how Composer can assist you in running them manually whenever required.

Let us consider the following example: as a first step, we would like to run PHP-CS-Fixer to automatically fix the code in our src folder. Afterward, we wish to run PHPStan with level 1 on our code as well. You could surely run both steps separately, but we want to add a bit more comfort and execute both tools in one go.

To achieve this, we can utilize the scripts section of the composer.json file in the project root. There, we have to add the tools we want to execute under a concise command name, such as analyze. The following example shows what this could look like:

{
  ...
  "scripts": {
    "analyze": [
      "vendor/bin/php-cs-fixer fix src",
      "vendor/bin/phpstan analyse --level 1 src"
    ]
  }
}

We used the JavaScript Object Notation (JSON) array notation here to add each command in a separate line, which makes it easier to read and maintain than writing everything in one line.

If you want to share these Composer commands, you might want to add a short description text as well, which is displayed when you execute composer list to see a list of available commands. To do that, you need to add the script-descriptions section to your composer.json file. For the previously introduced analyze command, it could look like this:

{
  ...
    "scripts": {
        ...
    },
    "scripts-descriptions": {
        "analyze": "Perform code cleanup and analysis"
    }
}

By installing the tools in a subfolder, we found a suitable way to organize our code quality tools without letting them interfere with our application dependencies. But what if, for whatever reason, you are not using Composer in your project, or you dislike the fact of having two composer.json files in your repository? In the next section, we will introduce an alternative way that does not make use of Composer.

Installing code quality tools as phar files

Composer is not the only possible way to add code quality tools to your project. In this section, we will show you to add the tools as phar files.

We already came across phar in the previous chapters. It stands for PHP Archive and can be considered a whole PHP project within a single file. Technically, it is a self-executable ZIP archive that contains the source code of the application plus all necessary dependencies as well. The big advantage is that the required code is available immediately after download, so you can instantly use any phar file right away without having to care about Composer or dependencies at all. Furthermore, phar files are supported by all modern PHP versions.

This makes the usage of phar files quite handy, as you can treat them like binaries. Usually, you can download the many PHP tools we introduced to you so far as phar files directly and place them in whatever directory you want. However, there is no unified way these files are provided, so please refer to the official documentation of each tool.

Let us have a look at how to do that for the phploc tool, which we introduced in Chapter 7, Code Quality Tools. According to its GitHub repository, you can simply download it from the PHPUnit website, as they are both from the same author. The following code snippet shows how you can do this:

$ wget https://phar.phpunit.de/phploc.phar -O phploc

Note that we install the tool under the name phploc, and not phploc.phar. The -O option allows you to specify a different filename than the one you are downloading. The .phar extension is not necessary to execute the tool, so you can save on a bit of typing effort here.

Phar and checksums

Downloading and executing files from the internet always includes the risk that they can be corrupted and infected with malicious code. That is why the authors of the tools often generate checksums (for example, through hash algorithms such as Secure Hash Algorithm 256 (SHA256)) of the downloads and publish them on their websites so that you can use them to verify the integrity of the download. Please check the official websites of the tools you’re considering using to find out if they offer checksums, and how to verify them.

Of course, you can download it using any method you like, be it curl or via the browser. Once you download it, you can immediately run it using your local PHP installation, like so:

$ php phploc src

If you do not want to type php every time, you need to make the phar file executable, which on Linux—for example—would look like this:

$ chmod +x phploc

Afterward, you just need to run the following command to execute phploc:

$ ./phploc src

Keeping your phar files organized

Now, we do not just want to download the phar files—we also want to keep them organized in our project so that any other developer does not have to do any manual work before using them. The most obvious choice is to add these files to your repository, and that is precisely what we will look at now. In the following example, we will use Git, but this approach would work with any other version control system (VCS).

It is generally discouraged to store large files in Git because they can affect performance negatively. GitHub, for example, blocks files that are greater than 100 megabytes (MB). However, the phar files we use are usually just a few MB in size, so adding them should not have any negative side effects.

Git Large File Storage (Git LFS)

If you need to store large files in Git, consider using Git LFS, which was designed exactly for this use case. For our needs, though, we do not have to use it.

You can freely choose where to add phar files to your project. A common place is the root folder; however, since this will get quite crowded over time, we recommend using a separate folder to store them. A good place would be the tools folder again, just like we used it in the previous section. You do not need to consider anything else; just add them to the repository like any other file.

Let us assume you copied the phploc file into the tools folder and made it executable as described previously. Then, you would just execute as follows:

$ tools/phploc src

Using phar files is easy and does not interfere with your application dependencies. However, they are not perfect: if you want to update them, you need to look up the download Uniform Resource Locator (URL), download the phar file, and validate its checksum manually every time—for each tool. In the next section, we will show you how to ease that process by introducing another dependency management tool: Phive.

Managing phar files using Phive

In the previous section, we learned about using phar files instead of using Composer to install our code quality tools. This approach works fine, but it does require some extra work in case you want to update them.

Phive is a tool that takes over that extra work. Let us install it right away.

Naturally, Phive itself can be downloaded as phar, too. The following commands will download it under the name phive and make it executable:

$ wget https://github.com/phar-io/phive/releases/download/0.15.1/phive-0.15.1.phar -O phive
$ chmod +x phive

Please note that this installation method is not very secure. Check the tool’s website (https://phar.io) to learn how to install it securely and how to make it globally available.

For demonstration purposes, the simple download works just fine. Once the file is downloaded and made executable, you can directly start using Phive to install the first tools. Let us use phploc, which we introduced in the previous chapter, to demonstrate how it works, as follows:

$ ./phive install phploc

Download verification

Phive not only takes care of the installation but also of the verification of the downloads. This is done automatically during the installation process. However, this requires the vendor to make the checksums available, which is also the main reason why not all tools can be managed through Phive.

As you saw previously, installing a tool is done just by using the install command. The following four things have happened now:

  1. Phive downloaded the latest version of phploc and verified its checksum.
  2. The phar file got stored in a shared folder (usually located in your home folder under the name .phive).
  3. Phive then created a symbolic link to that shared folder. A symbolic link is a reference in the filesystem so that a file or directory can appear in multiple directories, although it is stored in just one place. By default, this symbolic link is stored in the tools folder, which will be generated if it does not exist.
  4. Another .phive folder has been created in your project root folder, which is used to store the information about which tools have been downloaded.

Symbolic links appear just as “real” executables in your directory, while the original file stays in one single location. If you do not want to use symbolic links, you can install a file copy instead by using the --copy option.

After installation, the execution of phploc is simple, as we can see here:

$ tools/phploc src

Phive offers more useful commands. Just run the following code without any command to get a list of them:

$ ./phive

Here, we introduce the most important ones:

  • list—Lists all tools that can be managed through Phive
  • update—Updates all installed phar files, if newer versions are available
  • selfupdate—Updates the phive executable itself
  • outdated—Tells you which phar files can be updated
  • status—Lists an overview of all installed tools

Adding Phive to your project

If you work in a team, you not only want to locally install the phar files. Phive has got you covered here as well. Two steps are necessary to properly add Phive to your project, as follows:

  1. Add the .phive folder in your project root to your repository. The phars.xml file inside contains all necessary information (such as the composer.lock file).
  2. Make sure the tools folder is not under version control (for example, by using a .gitignore file). You explicitly do not want to add the phar files themselves to your repository.

Once this is done, the next time the project gets checked out from the repository, the tools can be installed by executing the following command:

$ ./phive install

This command can be easily integrated into other workflows—for example, as an additional post-install-cmd script in the composer.json file.

That is already all you need to know about Phive to start using it. As usual, we recommend you read the official documentation because we could not cover every feature it provides in this book.

Summary

Composer is an indispensable part of today’s PHP world. The usual approach to adding code quality tools to your project is by adding them to the require-dev section of the dependencies, which works fine in many cases.

However, Composer is not the one and only way there is. Therefore, in this chapter, we introduced two more options to manage your code quality tools: by adding the phar files manually to your project, or by utilizing Phive to manage the phar files.

You are probably eager to apply all your gained knowledge to your code now. However, relentless refactoring can do more harm than good, and clicking through all parts of your application after every change to check if anything broke will cost you a lot of time and can be very frustrating. Thus, in the next chapter, we will show you how automated testing can help you here.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset