May 07, 2014
Table of contents:
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.
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 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.
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.
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.
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:
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
.
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.
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.
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!