The PHP Standards Recommendations (called PSR) are a set of standards that aim to make certain aspects of working with PHP easier. They include things like coding standards (PSR-1), sending HTTP requests (PSR-7), and the autoloading standard PSR-4.
PSR-4 describes the ability to include PHP classes based on their file paths. This means that instead of manually including every class file you need, you can write an autoloader that will do this for you.
The key bits of information are the namespace and the name of the class. Using this information you can then look up and include the class you need as the code is running.
Taking an example of a class called Image, which has the namespace of Hashbangcode\Package\Type. This would look something like this:
<?php
namespace Hashbangcode\Package\Type;
class Image {
}
As the class is called Image, then the file that the class is stored in will be called Image.php. In order to not confuse matters we only have one class per file.
The namespace is split into the namespace prefix and the prefix of the class. In this example the "Hashbangcode\Package" part at the front of the namespace is the prefix, and is used to refer to the author and package name that this class exists in.
Putting this information together tells us that the Image class exists in the directory "Type" in the package directory. Which means the file at "src/Type/Image.php" would be included when we needed this class.
Note that PSR-4 is a standard, which means we have to write or find a package that will take care of this autoloading for us.
This is where composer comes into play.
Composer
Composer comes with an autoloader that understands PSR-4 and can be easily configured to understand where our code is. All we need to do is configure it and composer will handle autoloading our class files.
Following on from the previous example, the directory structure of our package currently looks like this.
src/
- Type/
- - Image.php
To set up composer we need to create a composer.json file that contains an "autoload" property. This points the namespace "Hashbangcode\Package" to the directory "src" in our project. Notice the use of the double \\ in the namespace setting, this is required as it helps to prevent any namespace clashing between similarly named namespaces. It also prevents the single slash from escaping anything in code since the backslash character also escapes certain characters.
{
"autoload": {
"psr-4": {
"Hashbangcode\\Package\\": "src/"
}
}
}
With this in place we can now dump out the autoload files that composer requires. This is done using the dumo-autoload command with the -o (a lower case O), which will optimise the autoloader based on PSR-4 classes.
composer dump-autoload
Running this command will generate a "vendor" directory that contains a bunch of PHP files used in the autoloading of classes.
In order to use the autoloader we just need to include the ./vendor/autoload.php file and start using classes that we have registered. In the example below we creating a new Image object after registering the namespace and including the composer autoload.php file.
<?php
use Hashbangcode\Package\Type\Image;
require_once('./vendor/autoload.php');
$image = new Image();
Adding Tests
Finally, it is also possible to tell composer about any development dependencies, which is important when adding unit tests to a project. It is generally considered bad practice to include your unit testing packages in your production code and so it's a good idea to de-reference your testing classes unless your development dependencies are installed.
This is done through the "autoload-dev" property of the composer.json file, which tells composer about the location of your tests when installed in a development context.
In the following example we have required PHPUnit as a development dependency, and also added our test classes using an autoload-dev.
{
"autoload": {
"psr-4": {
"Hashbangcode\\Package\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Hashbangcode\\Package\\Test\\": "tests/"
}
},
"require-dev": {
"phpunit/phpunit": "^9.5"
}
}
With this in place we can start adding tests to the "tests" directory in our project.
src/
- Type/
- - Image.php
tests/
- Type/
- - ImageTest.php
The ImageTest class will look something like the following.
<?php
namespace Hashbangcode\Package\Test;
use PHPUnit\Framework\TestCase;
use Hashbangcode\Package\Type\Image;
class ImageTest extends TestCase {
}
As PHPUnit also uses autoloading it will understand the namespaces we add here and automatically find the objects we create. All we need to do here is call PHPUnit with a reference to our tests to run all of the tests in the project.
Add new comment