- 6 min read

PHP : What are PSR for ?

PHP
Markdown logo

PSR are PHP Standard Recommendations published by the PHP-FIG (PHP Framework Interop Group).

Their purpose is to create public recommendations to ensure increased compatibility between projects, as well as common understanding of some specific concepts.

At the current time, they range from PSR-0 to PSR-22, some of which are deprecated, abandoned, or in development.

Code style

Among all PSR, we can find some recommendations for the code style to follow when writing an application.

The purpose is to make it easier for developers who work on multiple projects to read code with the same writing rules. Of course, no one actually has to follow them, but for open-source projects for example, it may be interesting to adhere to public standards, to attract more contributors and keep style consistency in the code.

Therefore, we will find PSR-1 or PSR-12, indicating which rules to follow, for example :

  • If a PHP file only contains PHP, do not end it with the ?> tag
  • Leave a blank line at the end of a PHP file
  • The abstract keyword must appear before the visibility for a class member
  • Visibility is mandatory for a class member
  • etc…

It is very difficult to learn and remember all the rules of a code style recommendation. Thus, tools can automate the verification and formatting of the code. For example, PHP-CS-Fixer (Coding Standards Fixer) can be used to do this.

Autoloading

Another standard recommendation is about loading classes.

The old way to load classes is simply to require_once the file. But it can quickly become very tedious to organize.

To answer this problem, we will use the PSR-4 recommendation, which is based on the file tree.

Namespaces

PSR-4 suggests to organize our classes under various namespaces.

Therefore, we can have classes like Symfony\Component\Mailer\Mailer or App\Shop\OrderService for example.

The classes in question are respectively Mailer and OrderService. They are just under different namespaces.

Consequently, we will declare a namespace for each class:

<?php
namespace App\Shop;

//...

class OrderService {
  /* ... */
}

And in another file, if we want to use OrderService :

<?php
// namespace... (another namespace if needed)

use App\Shop\OrderService; // Class inclusion

// ...

FQCN

For each class of our application, the PSR-4 recommendation creates a FQCN: Fully Qualified Class Name. It is the complete path from the root namespace to the class name.

How to organize our files ?

PSR-4 works with the file tree.

In fact, for each root namespace, PSR-4 will need a corresponding path. Then, for all namespaces that are below, it will simply follow the corresponding tree, until it reaches the class name.

Examples

In a project

In our own projects, we can declare and use an autoloader following the PSR-4 recommendation.

To do this, we will add the autoload section in composer.json file with the appropriate structure. For example, a commonly used structure consists in having a root namespace App\ associated to a folder src/. Thus, all our classes and our logic will be in the src/ folder. It is up to us to create new directories to organize sub-namespaces.

// composer.json
{
  //...
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  }
  //...
}

Then, we can create our classes in the src directory of the application.

In the Symfony Mailer component

In many projects, we will also find the PSR-4 autoloading rule.

For example, in the Mailer component of Symfony, if we take a look at the composer.json file :

{
  "autoload": {
    "psr-4": { "Symfony\\Component\\Mailer\\": "" }
    //...
  }
}

This configuration indicates that all classes or interfaces that are at the root of the Mailer project will have the namespace Symfony\Component\Mailer.

Interfaces

PSR can also define general interfaces, that anyone can decide to implement.

Let’s take the example of PSR-11: it is a ContainerInterface interface defining a contract to implement if we want to realize a dependency injection container. The goal, as indicated in the recommendation page, is to establish a standard for libraries and frameworks about how to use a service container to obtain objects and parameters within an application.

For example, the DependencyInjection component docs of Symfony state in their first paragraph :

The DependencyInjection component implements a PSR-11 compatible service container that allows you to standardize and centralize the way objects are constructed in your application.

If we take a look at the component code, we will also find all the information we are looking for.

Example : symfony/dependency-injection

Let’s explore the Symfony DependencyInjection component. It follows the PSR-4 autoloading rule, so we can easily navigate it.

We can find a dependency in the composer.json file, pointing to the psr/container package. It is the package actually containing the PSR-11 interface to implement.

Then, if we go to the root of the project, in the ContainerInterface class, we can see that it inherits the PSR interface. Moreover, they have assigned an alias to the PSR interface, since they wanted to create their own ContainerInterface, with the same name as the PSR one :

namespace Symfony\Component\DependencyInjection;

use Psr\Container\ContainerInterface as PsrContainerInterface;
//...

interface ContainerInterface extends PsrContainerInterface
{
  //...
}

We will therefore find the get and has methods, but also other methods like getParameter or set, for example.

Finally, if we go to the Container class, we will notice that it implements ContainerInterface.

Example : PHP-DI

If we go to the PHP-DI repository, another known dependency injection container in the PHP ecosystem, we find the psr/container dependency and the main class implements the same contract:

namespace DI;

//...
use Psr\Container\ContainerInterface;

class Container implements ContainerInterface, FactoryInterface, InvokerInterface
{
    //...
}

There are many other interfaces among all PSR, for example :

In summary, we will now know what it means for a library to state that it is “PSR-XX compatible”.