Home » Code » How to create a PSR-4 PHP package

How to create a PSR-4 PHP package

Posted by on May 7th, 2014

How to create a PSR-4 PHP package
Over the last couple of weeks I’ve wrote tutorials on many different aspects of the PHP programming language as building blocks for building your own packages. Understanding these different concepts will take you a long way when it comes to creating your own packages for your projects as well as for the Open Source community.

A couple of weeks ago I wrote a tutorial on the general principles behind building PHP packages. In that article I mentioned the PSR-4 standard for creating PHP packages.

In this tutorial I’m going to walk you through setting up the structure of a PHP package. By having an agreed upon structure for PHP packages we make our code a lot more interchangeable and reusable for the greater Open Source community.

The directory structure

So the first thing to do is to create a new directory on your computer that will hold all of the files. For the purpose of this tutorial I will call my package Nacho.

So firstly, create a new directory called nacho.

Open the nacho directory and create two more directories called src and tests.

All of the code of the package should reside in the src directory and all of your package’s tests should live in the tests directory.

Next, open up your command line and run:

git init

This will create a new Git repository. Git is a requirement for creating PHP packages so I’m going to assume you already have it installed.

Composer

Composer is a PHP package manager that plays a pivotal role in how we pull dependencies into our projects. If you are unfamiliar with Composer, read What is PHP Composer? before continuing on with this tutorial.

Create a file under the nacho directory called composer.json and copy the following code:

{
    "name": "philipbrown/Nacho",
    "description": "Nacho, nacho man. I want to be a nacho man",
    "license": "MIT",
    "keywords": ["nacho"],
    "authors": [
        {
            "name": "Philip Brown",
            "email": "name@domain.com"
        }
    ],
    "require": {},
    "require-dev": {
        "phpunit/phpunit": "4.0.*"
    },
    "autoload": {
        "psr-4": {
            "PhilipBrown\\Nacho\\": "src"
        }
    }
}

The composer.json file defines meta data about the package. As you can see from the text above, we specify a name, description, license as well as who is responsible for the package.

The three most important sections of this file are require, require-dev and autoload.

require is where you list any dependencies that your package will require.

require-dev is where you list any dependencies that are required to develop your package. In this example I’ve listed PHPUnit which will be used for writing tests.

And finally, autoload specifies how your package should be autoloaded. Composer can handle autoloading your files, but you need to specify how you want it to work. In this example I’ve specified to use psr-4.

Once you have the file saved, go to your command line and run:

composer install

This will create a new directory called vendor and pull in any dependencies that you have requested.

Dot files

Now that you have specified your project’s dependencies and pulled in a local copy using Composer you have what you need to start developing your package.

However, when it comes to distributing your package, you only care about your code and not the dependencies that you’ve pulled in.

Committing your vendor directory to your Git repository would mean a lot of duplicated code when your package was pulled into someone else’s project.

Git allows you to specify which files or directories that you don’t want to include in your repository through a .gitignore file:

/vendor
composer.lock

In this example I’m specifying that the vendor directory and the auto generated composer.lock file should not be included in the Git repository.

If you are going to be hosting your package on GitHub a nice free feature is the ability to integrate with Travis CI, a continuous integration application that will run your tests for you. This is really useful when you start accepting pull requests as you will be able to quickly see if all the tests are passing right from GitHub’s interface.

To integrate with Travis, add a new file called .travis.yml and copy the following text:

language: php

php:
  - 5.4
  - 5.5
  - 5.6
  - hhvm

before_script:
  - composer self-update
  - composer install --prefer-source --no-interaction --dev

script: phpunit

I won’t go into depth about using Travis in this post, but this should be a good start for you to explore the service for yourself.

Your code

Now you are ready to write your code. Open the src directory and create a new file called Nacho.php.

Copy the following code into that file:

<?php namespace PhilipBrown\Nacho;

class Nacho {

  public function hasCheese($bool = true)
  {
    return $bool;
  }

}

If you have ever looked at the source code of older PHP packages, you would of been expecting a PhilipBrown directory and then a Nacho directory. PSR-4 has done away with that nested directory structure and instead allows you to write your classes directly under the src directory.

Writing tests

Now that we’ve got the code of the package set up, we can start to write some tests. PHPUnit requires a file called phpunit.xml in order to define some settings. Create a new phpunit.xml file in the root of your directory and copy the following code:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false">
    <testsuites>
        <testsuite name="Nacho Test Suite">
            <directory suffix=".php">./tests/</directory>
        </testsuite>
    </testsuites>
</phpunit>

If you are unfamiliar with the xml in this file, don’t worry about it, you don’t really need to know what’s going on. This file is basically just defining some settings to use and how the files should be autoloaded.

Next under your tests directory, create a new file called NachoTest.php and copy the following code:

<?php

use PhilipBrown\Nacho\Nacho;

class NachoTest extends PHPUnit_Framework_TestCase {

  public function testNachHasCheese()
  {
    $nacho = new Nacho;
    $this->assertTrue($nacho->hasCheese());
  }

}

Open up your command line and run:

vendor/bin/phpunit

PHPUnit should automatically run the test and give you a green “all tests passed” output.

When writing your tests you need to ensure that your test class extends PHPUnit_Framework_TestCase.

Documentation

The final thing to do is to create a readme.md documentation file. If you are going to be hosting your code on GitHub, this file will be automatically displayed first, so it’s a good way of describing your package, what it does and how it works.

You should also include a license with your open source code. By default, anything you put out into the world is your copyright, so if you want to allow other people to use your code, you need to put a license on it. A good choice is the MIT license.

Pushing to GitHub and Packagist

Now that you’ve finished your package you can push it to GitHub and to Packagist.

GitHub is a hosted git repository service that makes it really easy to collaborate on software.

Packagist is a central directory to find and use PHP packages.

To push your repository to GitHub, create a new repository.

You will be given instructions for adding an existing git repository to GitHub. To push your repository, you will need to run the following two commands from the command line:

git remote add origin git@github.com:username/nacho.git
git push -u origin master

To integrate Packagist and Travis with your repository on GitHub, you need to go into Settings, and then find the two services in the Webhooks & Services section. To integrate both of these services you just need to authenticate your GitHub account and follow some simple instructions.

Conclusion

If you have never developed a released a PHP packaged before, this can be a lot to take in. However, once you’ve set up this process more than once, it becomes second nature.

The structure of a PHP package is really quite simple, and PSR-4 has made it even simpler. Once you know what each bit of the structure is used for, reading through someone else’s PHP package becomes a lot easier.

PHP suffered for many years by not having this package approach to releasing open source software. Nowadays it’s a breeze to pull in someone else’s package so that you don’t have to reinvent the wheel.

Next week I’m going to look at what goes in to a real world PHP package, using lots of the theory that we’ve been looking at for the last couple of weeks!

Philip Brown

Hey, I'm Philip Brown, a designer and developer from Durham, England. I create websites and web based applications from the ground up. In 2011 I founded a company called Yellow Flag. If you want to find out more about me, you can follow me on Twitter or Google Plus.

  • Philip thanks soo much. These tutorials help me alot and thanks for all the explanations.

  • Voodoo

    Great article!

  • Hey Philip, just a comment. As said in Composer documentation, it’s good practice to commit the composer.lock file to your repository https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file

    • Yep when shipping an application it’s good to have that file in your repository.

      You don’t want to do it for packages though.

      • Adding it to the repository has any downsides (when developing packages)? I know is not necessary is most cases, but I don’t see any problem having it either.

        • True, I don’t think it can hurt. Most packages you see don’t commit it though.

  • This is a great tutorial and it’s exactly what I was looking for.

    However, I’m still a little confused about the naming conventions. If my vendor namespace is Aalaap, will my package name by Sample-Package-Name or SamplePackageName? How exactly do I state the class name and/or function?

    If you could update your example to demonstrate creating a NachosWithCheese package, it’ll be immensely helpful! :-)

    • I’m not sure what bit you are confused about? Could you elaborate?

      • I’m confused about how to go about naming packages or classes with multiple words. Camel case? Hyphens? Snake case?

        • Ah I see, yeah it would be SamplePackageName, so camelcase with a starting capital letter :)

  • subdural

    Great article, Philip! Quick question: what do you do about versioning? Is it better to tag versions via git or specify a version in the composer.json file? Is there a best/standard practice?

    • Thank you :) You should tag versions in git, and then consumers of your package can specifiy which version they want.

  • refschool

    hello,
    that means for your own project your proprietary code should be in src/ ?

  • But, How I can use it? I try to use it like

    use PhilipBrownNachoNacho;

    $nacho = new Nacho;
    dd($nacho->hasCheese());

    But I got an error like the following

    Class ‘PhilipBrownNachoNacho’ not found

    What is wrong with me? How I can use it?

  • David Zamora

    I really liked it, there are not too many articles about this topic. Thanks!

  • Klyukin Stanislav

    If you have class not found after some renaming – you possible need to run

    `composer dump-autoload`

    • Yeah, that’s always the first thing I try too! :D

  • aprillins

    This is the best article I’ve ever read, not just about creating php package but also its relationship to the travis, git, and phpunit. Very easy, concise, and clear. Should find more article like this on Google.

  • Erp Restrepo

    He tenido algunos problemas con Travis Ci pero de alguna manera le encontrare solución muy buen aporte http://calimaframework.com

  • Hello Philip,
    You wrote “PSR-4 has done away with that nested directory structure and instead allows you to write your classes directly under the src directory.”

    I saw http://www.php-fig.org/psr/psr-4/ and they suggest to use nested directory structure in case you use sub-namespaces.
    I am not sure why, but I guess they way you suggested will only work with composer psr4 autoloader and not when loading a file that corresponds to a fully qualified class name as suggested in above link.

    • Hmm, I’m not sure what you mean, do you have an example?

      • I mean, Do i need to maintain the directory structure according to namespaces in case I am not using psr4 auto-loader created by composer in vendor directory

        • Ah right, well if you are not using PSR-4 autoloading you can do anything you want. I would just stick to using the standards though.

        • I think what Sanjay means is can he not use the src folder and still be PSR-4 compliant, whilst retaining backwards compatibility with past PSR’s

      • kazi t ahsan

        http://www.php-fig.org/psr/psr-4/ and it suggests the nested directory structure.