Now that PHP 7 has been released, you'll no doubt want to start taking advantage of all of the improvements that this newest version of the language provides.

This brief guide will help get you started on the road to developing awesome applications written in PHP 7 by walking you through the process of setting up a PHP 7 flavoured development environment.

For this guide, I'll be using these resources:

  1. Virtualbox as a means of hosting a virtual linux server
  2. Vagrant as a means of controlling your shiny new virtual server
  3. Homestead, Laravel's own server image for Vagrant, since it is so good.

Obtaining Virtualbox

Virtualbox is just one way of providing a virtualised server environment within your local development environment. Others cross platform offerings include the commercially available VMWare and the awesome Docker. I'm using Virtualbox with Vagrant though as it's super easy to get going with.

For this section, we need only do two things.

  1. Download the latest Virtualbox version for your development machine
  2. Install it.

How you install it depends upon whether you're running on Mac, Windows or Linux. After the installation is complete, return to this page.

Install Vagrant

Vagrant is the awesome add-on utility that allows you to control the virtual servers that you set up within Virtualbox. We'll get to how you use it soon, but first you need to install it.

As with Virtualbox, just pop along to the Vagrant downloads page and select the right installer for your "host" system.

When we talk about the host and the guest systems, we're simply referring to:

  • host: This is your machine and the operating system installed on it.
  • guest: This is the virtual machine and its operating system that we run inside Virtualbox.

To confirm that Vagrant installed ok, just head on over to the command line and execute:

$ vagrant -v

// Output:
Vagrant 1.8.1

As long as Vagrant reports a version number, we should be good to go.

Setting up our development folders

Before we get to add the actual virtual server to our Vagrant setup, let's take a moment to create our working directories. You can name and organise these however you like, but for me the directory structure that I prefer, and use for this guide, looks like this.

./Development
    projects/
    servers/
      php7/

In other words, I first create a directory called Development (on my mac, the full path is /Users/thunder/Development) and inside of this directory, I create the projects and the servers/php7 folders.

The projects folder is where I will do the active development on the various projects that I work on.

The php7 folder is just a convenient location for me to store my principle Vagrant config file. We'll get onto that shortly. Our next task is to get the virtual server installed.

Getting the Laravel Homestead image for PHP 7

Don't worry about it being called the Laravel homestead image; this thing doesn't force us to use the Laravel framework for developing in. Instead, those lovely chaps over at Laravel have kindly made this vagrant image available to all. The image comes prepackaged with lots of goodies inside including the MySQL and PostgreSQL database servers, the redis and memcached key value stores and the all important PHP version 7, all ready to go.

Before we add this virtual server via the command line, we want to cd into the php7 directory that we created in the previous step, so do that now.

cd /path/to/Development/servers/php7;

Once we're in the right location, adding the homestead virtual server image to vagrant is a simple one-liner.

$ vagrant init laravel/homestead-7; vagrant up --provider virtualbox

This will do a number of things.

First of all, it will create a default Vagrantfile in our current directory. This Vagrantfile will be automatically set to use the laravel/homestead-7 image.

The second thing that this one-liner does is attempt to start the virtual server image specified in the Vagrantfile that the init stage created. If your copy of Vagrant doesn't yet have that image available (it won't), vagrant will attempt to download it from the central image repository hosted on atlas.hashicorp.com. Once the image has been downloaded and installed, vagrant proceeds to fire up the virtual server.

If all goes well, you should see a lot of output on the command line corresponding to what vagrant is doing with the virtual server. As long as you see the following line, all should be well.

====> Machine booted and ready!

We are almost there! But let's stop the virtual server and do a little extra config. We can use vagrant to stop the server for us and the command is a super easy one: vagrant halt.

$ vagrant halt
==> default: Attempting graceful shutdown of VM...
$

After a short wait, vagrant should tell us that it is attempt a graceful shutdown of the VM, just like the above.

Now let's do a little configuration.

Configuring the Vagrantfile

If we open the Vagrantfile inside the php7 folder, we can see a whole bunch of settings and comments for the various options available to us. As this is a super easy quick setup guide, we're just going to look at two sections.

The first has to do with port forwarding. In simple terms we're providing a map between the tcp ports in the VM and the tcp ports we would like to use on our development machine.

Forwarding ports

For example, if we want to view our PHP 7 development efforts in our web browser, we need to forward port 80 on the guest virtual server to an appropriate port on our development machine. To avoid any conflicts with low port numbers and permissions, let's make that port 8080 on our local host machine.

To achieve this, find this line near the top of the Vagrantfile

# config.vm.network "forwarded_port", guest: 80, host: 80

Uncomment it, and change it so that the host value is set to 8080, like this.

config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 3306, host: 33060

You'll notice that I've also forwarded the default MySQL port (3306) to port 33060 on my local machine. This is so that I can easily access the MySQL server instance inside the VM through MySQL Workbench later on.

Sharing the projects folder

The second thing that we need to do is to set up folder sharing between the host file system and the virtual machine's filesystem. Locate this line in the Vagrantfile (hint: it's roughly in the middle)

  # config.vm.synced_folder "../data", "/vagrant_data"

Uncomment this line and then change the paths to read like this

   config.vm.synced_folder "../../projects", "/vagrant/projects"

The first path (../../projects) corresponds to the path to our projects folder that we created earlier on. Do note that this is the relative path from the directory containing the Vagrantfile; this is important. The second path (/vagrant/projects) corresponds to the file system path that vagrant should mount the shared folder at.

These are the only two edits that we need to make to our Vagrantfile at this stage. Let's bring up the virtual machine. The command to do this is also super easy

 $ vagrant up

If all goes well, you should see a familiar bunch of stuff in your terminal window as vagrant goes through the process of booting the virtual machine. If you watch this output closely, you should be able to see vagrant setting up the port forwarding and sharing the projects folder that we specified.

Our next job is to configure a virtual host in Nginx, our web server software of choice.

Adding a virtual host to Nginx

The homestead image comes with a script that's designed to make adding virtualhost definitions to Nginx super easy, but I prefer an even easier way to do it by adding a 'one vhost fits all' style config.

First of all, we need to ssh into the virtual machine. As you might expect, this is pretty easy

$ vagrant ssh
...
[email protected]:~$ 

We're now at the command line inside the virtual machine. Copy and paste the following command (without the leading $ sign) and press enter.

$ sudo nano /etc/nginx/sites-available/local.app

What you should see now is mostly a blank screen. This is nano, a very lightweight and noob-friendly text editor. If you're already comfortable with something a little less noobish, such as vim or emacs, go ahead and use that instead.

In any event, the following virtualhost definition needs pasting in to this text file, so go ahead and copy/paste.

server {
    listen 80;
    server_name ~^(www\.)?(?<sname>.+?).local.dev$;
    root /vagrant/projects/$sname/public;

    index index.php index.html;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log /var/log/nginx/$sname-access.log;
    error_log  /var/log/nginx/wildcard-error.log debug;

    error_page 404 /index.php;

    sendfile off;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

If you're still in nano, press CTRL+O (letter O) to save the file, and then CTRL+X to exit nano.

Before we move on, just one thing to note about that config, so let's take a look at lines 2 and 3 next

server_name ~^(www\.)?(?<sname>.+?).local.dev$;
root /vagrant/projects/$sname/public;

These two lines tell Nginx that when it sees a request for http://www.(projectname).local.dev, it should try to serve the web site with files located at the path `/vagrant/projects/(projectname)/public.

Note. The server_name pattern also makes the 'www' prefix optional. So, http://www.myapp.local.dev would be treated exactly the same as http://myapp.local.dev

In this way, we can create as many applications as we like under the projects folder in our working directory and each project's root folder will become the sub-domain to use to access the site with.

Now we just need to run two more commands inside the virtual machine. The following command places a symlink to the local.app config file in the sites-enabled directory, telling nginx that this is an active virtual host definition.

$ sudo ln -s /etc/nginx/sites-available/local.app /etc/nginx/sites-enabled/

And the next command tells the Nginx web server to reload its config, which will also load in our new virtual host definition.

$ sudo service nginx reload

That should be the last time that we need to configure Nginx for a good wee while so let's get out of here. Type exit at the command line to exit the VM

$ exit

Final steps

We're pretty much ready to go. All we need for the final stages are a name for a project to start building in PHP7.

Let's get really creative and call it "myapp".

The first thing that we need to do is modify our development machine's hosts file so that it knows where to find "myapp.local.dev". On a mac or a linux box, this is easily done by opening a terminal window and typing the following command:

$ sudo nano /etc/hosts

Ooh look, nano again. The noob is strong with this one.

Elitism against simple text editors aside, just add the following line to the hosts file, then save and exit just like before

127.0.0.1 myapp.local.dev

With that in our hosts file, we're ready to browse to our new PHP 7 app. Except... we haven't made it yet.

So let's do that now.

Creating our first project's directory

This really is the last last step. Honest guv!

Change to the projects directory that you made at the beginning. This directory is the root of all the awesome PHP 7 projects that you're going to build on this machine.

Right now though, we need to create the directory structure for the myapp project. Remember that we configured Nginx to look in this directory for project files to serve and that we mapped the subdomain directly to a folder name located in this projects directory?

So, if we want to be able to see http://myapp.local.dev in our browser, we must create our myapp project's root directory here with exactly the same spelling and case. In other words, we need a directory with the exact same spelling as the myapp subdomain.

$ mkdir myapp

Finally, because we told Nginx that the virtual host's document root is the public folder inside the project folder, we need to create the public directory too.

$ cd myapp;
$ mkdir public;

Now that we've got the document root in place for the myapp project, let's create our first php file inside there, just so that we can confirm that everything works ok.

$ cd public;
$ nano index.php

(Yes, nano again!). Add the following two lines to index.php

<?php
phpinfo();

Save and exit, the same as before (CTRL+O, CTRL+X)

And we're done. Open your favourite browser and navigate to the following address: http://myapp.local.dev:8080/

All being well, we should see the output from the phpinfo() function confirming that we're running a PHP 7 web server.

Now fire up your favourite IDE and go make myapp into something awesome.

Finally

Due to the way that we created the virtual host definition for Nginx inside the vm, adding a second, third or fourth project to work on is as simple as repeating the last two steps.

  1. Add an entry to our development machine's hosts file 127.0.0.1 app2.local.dev

  2. Create the corresponding directories under the projects folder.

     ./Development
       projects/
         app2/
           public/
             index.php
    

And that's it! We can now build multiple, yet equally awesome PHP 7 projects on our local machine with just a simple, four step process

  • Edit hosts file
  • Create project directories and files along the lines of $projectname/public/index.php
  • cd ./Development/servers/php7;
  • vagrant up

Last words

There's a reason why I created the php7 folder inside the servers folder; it makes it very easy to add different images to vagrant with different software versions. Consider the following directory structure:

Development/
    projects/
    servers/
        php7/
        php5.6/
        hhvm/

With your application code nicely squirrelled away inside the projects folder, you can easily vagrant up different versions of PHP (or indeed other server configurations) and test your application code accordingly.

Of course, this isn't a replacement for the proper configuration management that can be achieved with the likes of Ansible, Chef and Puppet, but it's a start in the right direction and is definitely a much better setup than trying to develop for multiple PHP versions under the likes of WAMPP, XAMPP and MAMPP.

I hope this article proves helpful. Comments, questions, criticisms and corrections are most welcome in the comments below.