In just a few weeks, PHP 7 will be released on the world. At the time of this writing, PHP 7 RC 3 is out and RC 4 will be out by the time you’re reading this. The plan is to release PHP 7 in November. There are a number of new features and functions included with PHP 7 that we’ll talk about, as well as a few backward compatibility breaks that you’ll want to be aware of when upgrading to PHP 7.

Introduction

If you’ve kept up with PHP releases, you’re running code on PHP 5.6 right now. And the next version is 7. What gives? Did PHP developers forget how counting works? Nope. Quite a while ago, PHP 6 was a thing. Or rather, it was on its way towards becoming a thing. One of the major improvements with PHP 6 was going to be full unicode support, and a large effort went into making this happen, but it was not successful. Ultimately, many of the other upgrades that were planned for 6 ended up in PHP 5.3. Through a series of decisions and politics and what-not that you’re welcome to look up on your own, the source code branch containing PHP 6 was ultimately deleted.

However, there were quite a few books released which tried to capitalize on the upcoming release of PHP 6. (As a side note, take a look at my review of PHP 6 Fast and Easy Web Development on Amazon if you’d like to see what I thought of one of these books). When the time came for the release of the next major version of PHP, it came to a vote and it was decided that since PHP 6 used to be a thing that we’d be skipping 6 and moving on to PHP 7.

So, here we are. PHP 5.3 released in January 2012 is no longer supported at all. PHP 5.4, released in March 2012 is now longer supported either as of a few days ago. PHP 5.5 was released in June 2013 and is now only receiving security fixes. After July 10, 2016, it will no longer be supported. PHP 5.6 was released August 28, 2014 and will be actively supported until August 28, 2016 and receive security fixes for one more year after that. So while it’s not critical that you upgrade to PHP 7 immediately after release, getting familiar now will make it easier to know what to look out for and hopefully get you excited for what will be working in PHP 7 when you do upgrade.

Backward Incompatible Changes

For most scripts, upgrading to PHP 7 should be pretty simple. However, there are a number of items that you may want to be aware of. For the full list, please take a look at http://php.net/manual/en/migration70.incompatible.php.

Variable Handling

The first change that may affect your scripts are changes to variable handling. PHP 7’s parser is brand new and is what’s known as an Abstract Syntax Tree (AST) parser. This change was made to make handling code more consistent and to allow for new features and functionality that would not be possible using PHP’s old parser. The change to variable handling is that now variables are resolved in a left-to-right order. In all the previous versions, variables were resolved in special ways based on particular special cases. While many of us have gotten used to this and intuitively know how a particular variable would be interpreted by PHP, the new way is consistent. Let’s take a look at the differences:

Expression PHP 5 PHP 7
$$foo[‘bar’][‘baz’] ${$foo[‘bar’][‘baz’]} ($$foo)[‘bar’][‘baz’]
$foo->$bar[‘baz’] $foo->{$bar[‘baz’]} ($foo->$bar)[‘baz’]
$foo->$bar[‘baz’]() $foo->{$bar[‘baz’]}() ($foo->$bar)[‘baz’]()
Foo::$bar[‘baz’]() Foo::{$bar[‘baz’]}() (Foo::$bar)[‘baz’]()

Let’s talk about these examples for just a bit. In the first example, $$foo['bar']['baz'], PHP 5 would deal with $foo['bar']['baz'] and then use that result as a variable variable (hurk!). With PHP 7, first the variable variable $$foo is translated and then the array indices are applied.

In the second, $bar['baz'] is resolved and that value becomes the object property name for $foo. In PHP 7, the $bar field of $foo is found, and then the baz array key is found. The next 2 examples continue to show weirdness that we all had to remember or experiment with in order to work with the values we are expecting. With PHP 7, reading left to right works in all cases. If you need to resolve variables in the same way PHP 5 does it, you can use parentheses or curly brackets to make the variable resolution work the same way in PHP 5 or 7.

Changes to List

I feel like there are some of you who this may affect, but for most, this change won’t cause any issues. Firstly, list now assigns variables in the order listed instead of in reverse order. Since this probably doesn’t make any sense or you may not understand, a simple code example may make this clear. Again, for most of you who have nothing like this in your code, this may make no difference.

list($a[], $a[], $a[]) = ['a', 'b', 'c'];

For PHP 5, the $a array would be ['c', 'b', 'a']. Who knew? In PHP 7, it will be in the expected 'a', 'b', 'c' order. Additionally, list constructs can no longer be empty. In the past you could do list() = [1, 2, 3]; or list(,,) = [1, 2, 3];. I’m not sure why you’d do that, but you can’t any more. If you were using list to unpack strings, that won’t work any more in PHP 7 either, and it is now recommended you use str_split instead.

Other Backward Compatibility Breaks

In the interest of time and because it’s much more interesting to learn about new features than ones that are broken, I’ll just briefly touch on some of the remaining backwards compatibility breaking changes. Starting with PHP 7, you can only use global with simple variable values. In PHP 5 you could use variable variables with the global keyword, but that sounds like a double headsmack. Once for using global and the second for using variable variables.

In PHP 5, you could make some strict standards errors not show up by wrapping function calls in parentheses before sending it into a function that was expecting a value passed by reference. In PHP 7 you cannot do that. Parens will no longer make the function behave differently.

The foreach keyword will no longer move the internal array pointer when it’s iterating over an array. It will also by default operate on a copy of the array, which means changes to the array that happen while iterating will not affect the values you are iterating over. However, it also has improved the iteration behavior when using foreach by reference. If you append values to an array while iterating over it with foreach and using by-reference, the foreach will now catch the newly appended values.

PHP 7 will treat integer values in a more sane way. In PHP 5, if you had a value of 0128 which, due to the leading 0 would be parsed as an octal value, the value would be truncated to 012. In PHP 7 you’ll see a parse error. If you try to bitshift by negative values in PHP 7 you’ll now get an ArithmeticError. Similarly, if you bitshift a number (in either direction) by more than the width of the value, you’ll end up with 0. Additionally, strings that contain values that could be read as hex values will no longer automatically be converted to their decimal equivalent. This means that var_dump('0xDEADBEEF' == '3735928559'), which gives a value of true in PHP 5 is false in PHP 7. Similarly, an is_numeric check on ‘0xDEADBEEF’ in PHP 7 is false.

If you’re expecting hex values to come in via string, you can use filter_var to check the values:

$str = '0xDEADBEEF';
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
var_dump($int); // int(3735928559)

Dividing by zero in PHP 7 will now throw a DivisionByZeroError exception.

There are several more backward compatibility breaks that you can look at here: http://php.net/manual/en/migration70.incompatible.php. The only other changes of note would be that classes, interfaces and traits should no longer be named any of bool, int, float, string, null, true, or false. This means the name of the class without any regard given to a namespace. For instance, Zend\Validator\Int is no longer valid in PHP 7. It is also recommended that you not name your classes resource, object, mixed, or numeric. Those are not keywords yet, but they are reserved and should be considered deprecated.

The Good Stuff

Let’s get on to the fun things, the new bits in PHP 7 that we couldn’t do before. But first, I want to throw this out there. PHP 7 is benchmarking as 2 times as fast as PHP 5.6. Let me say that again - 2x as fast as the current version of PHP 5.6. If the features we’re going to talk about aren’t enough to convince you, consider what it could mean for your application if PHP ran twice as fast. Ok, on to the fun stuff.

Scalar Type Declarations

For quite some time, we’ve all been used to having the ability to “type-hint” interfaces and classes in function and method calls. We’ve even been able to specify that an argument should be an array or a callable, but we couldn’t force a parameter to be a string or a number. PHP 7 brings scalar type hints which means now we can specify that a function expects int, bool, string and float. However, you are probably also aware that PHP has been a bit “loosey-goosey” on types. It will automagically change types behind the scenes as needed which can sometimes be very convenient and other times lead to really bizarre behavior that is hard to track down and tough to even think through unless you’ve run into it before.

This isn’t to say that you’re now forced to only sending in 7 if the function asks for an int, when old PHP would let you send in ‘7’. You now get the choice of how PHP should behave in the face of these type declarations. By default, PHP will act mostly just the way it has. Let’s take a look at a simple example.

function printInt(int $intval)
{
    echo $intval;
}

If I declare this function in a file and call it with ‘7’, PHP coerces the string 7 into the number 7 and my function receives and outputs the number 7. If I instead try to pass in ‘banana’, I get a new error: Uncaught TypeError: Argument 1 passed to printInt() must be of the type integer, string given

In PHP 5, first of all, we’d have to do all the type checking, casting, etc and decide how we wanted to deal with values that are passed in. This includes values that could be interpreted as something we can work with versus all the other types of junk that could be sent into a function. So in PHP 7, by default we get “coercive” scalar type declarations. However, we can also use strict type declarations. To enable strict scalar type declarations, we put the following directive at the top of any files that we want to use strict type hinting:

declare (strict_types=1);

Now with the same function, if I call it with anything other than an actual integer (meaning even the string ‘7’ will trigger this error), we’ll see the same error as above. So why would you ever want to do this when PHP can deal with all that nasty type juggling behind the scenes and convert our ‘7’ and ‘42’ into perfectly valid integers? Being more strict with our types gives the code more control. It’s much easier to deal with a value if we know what it is than if we have the whole universe of possibilities to work with and need to narrow it down into a small subset of allowable inputs. With coercion, we have no way of knowing in our function that what was passed in wasn’t 4.5 or 4.2 or ‘4.01’ because the function will just see 4. By making the code explicit about what types we want and letting PHP enforce that strictly, we will also see better tooling and support (think IDEs with better type-hinting and error checking) which will allow us to write better code with fewer bugs.

Other strongly typed languages have editors that can tell you as you’re typing if you’re making a mistake and sending in a value that could not possibly work. Part of PHP’s popularity and appeal was because we didn’t need to worry about any of that nonsense, our scripts would just “work”. However, whenever there was input that didn’t conform to the assumptions we’ve made in the code, the subsequent bugs, crashes and undesirable behavior became that much harder to track down and eliminate. It may seem weird at first, but I’d recommend turning on strict_types and seeing how you can make your code work. It may make you a better developer.

Return Type Declarations

Another amazing new feature in PHP 7 is the ability to tell the language (and other developers and IDEs) what a function or method is going to return. Those of us who use PHP docblock comments have long been using @return to help with that communication, but a comment annotation is not enough. There’s nothing about the comment that will enforce that I actually have to return what the comment says I will. With return type declarations in PHP 7, now the language can enforce that we’re returning the right stuff. This means that other developers or code that integrates with our functions can rest assured that what we said they’ll get is actually what they’ll get.

Depending on what other languages you’re familiar with, the syntax for declaring return types in PHP may look completely foreign and weird, or you may feel right at home. As opposed to C, C++ and Java which list the return type before the function declaration, PHP puts the return type at the end, like so:

function sumValues(int ...$addends): int 
{
	$sum = 0;
	foreach ($addends as $addend) {
	    $sum += $addend;
	}
}

We can declare the return type at the end with : int. We can also declare a return type of interfaces, classes, or other scalars. What we can’t do with this is declare multiple return types (although mixed is still allowed, it doesn’t really tell anyone anything useful).

Take another look at the function above. If you were to put this into PHP 7 and run it, you’d get an error right away. Fatal error: Uncaught TypeError: Return value of sumValues() must be of the type integer, none returned. I can’t tell you how many times I have made mistakes like this: build a function, do all the work and then completely forget my return statement. As I’m writing this, my code editor doesn’t alert me to this error, but I think it’s possible that it may be able to do that in the future. PHP, however, can tell me that I’ve screwed up. Adding in the return $sum; line to the end of the function will fix the error.

I’m pretty excited about both scalar type hinting and return type declarations, but that’s not all. PHP 7 is bringing even more to the table.

Null Coalesce Operator

Another great addition to the language is the null coalesce operator. If you care about preventing PHP from emitting notices for using variables that aren’t set yet (and you should, friends don’t let PHP spew notices) you’ve probably written this sort of pattern thousands of times:

if (isset($_GET['something'])) {
	$myParam = $_GET['something']; 
} else {
	$myParam = $someDefault;
}

Or the ternary equivalent:

$myParam = isset($_GET['something']) ? $_GET['something'] : $someDefault;

With the lovely null coalesce operator, this becomes:

$myParam = $_GET['something'] ?? $someDefault;

That’s it. But not only that, suppose you’ve got to check a number of difference places or values you may want to use based on the value being set. You can chain these together:

$myParam = $_GET['something'] ?? $_POST['something'] ?? $someDefault;

It’s beautiful, and it’s going to make code more expressive with a lot less code.

Spaceship Operator

Arguably the feature with the coolest name is the “spaceship operator”. The official name on the RFC was the “Combined Comparison Operator” but spaceship operator is cooler despite not giving any clue about what it’s for. The idea behind the operator is that it will allow you to compare two values and get one of three possible return values. If the two values are equal, you’ll get a return value of 0. If the first value is less than the second, it will return -1. If the second value is less than the first, then you’ll get 1. Where this comes into play is when you need to sort values, likely using PHP’s usort function. The usort function sorts values by comparing them using a provided comparison function.

Often the functions provided are not correct (but it’s not readily obvious). For instance:

function compare($a, $b) 
{
	return $a => $b;
}

The function above will not work properly in all cases and the resulting “sorted” array may not end up sorted how you think it should. Instead, the correct function would be something more like:

function compare($a, $b)
{
	return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}

So while that’s not terribly long to write, it’s ugly and not immediately clear what the intention is. The spaceship operator comes to the rescue:

function compare($a, $b)
{
	return $a <=> $b;
}

It doesn’t stop there though. If you wanted to implement a comparison function that would sort by multiple object fields or sub array keys, your function is going to be more complex. The spaceship operator makes this comparison simple and straight-forward. Imagine the compare function is looking at a couple of objects with three different fields to sort by:

function compare($a, $b)
{
	return [$a->f1, $a->f2, $a->f3] <=> [$b->f1, $b->f2, $b->f3]
}

Again, this operator is going to help make code much more expressive and succinct. It’s great.

Anonymous Classes

It’s been possible in PHP for quite some time to define anonymous functions and closures to various degrees. With PHP 7, it’s now possible to define anonymous classes. It may not be immediately obvious why you’d ever want an anonymous class, but they can be useful. In a similar use-case to anonymous functions, when you need to define a bit of functionality in one place and don’t need to go through the trouble of creating a function in a file somewhere just to pass it in to some other class or function, the anonymous class can be built on-the-fly and passed in to a function or method that is typehinting on some class or interface.

Suppose you’ve got a function that needs a logging class.

public function setLogger(LoggerInterface $logger)

Instead of finding or creating a new class and instantiating it, you could call it and pass in an anonymous class:

$object->setLogger(
	new class implements LoggerInterface {
		public function log(string $message) {
			echo $message;
		}
	}
);

The $object instance can now “log” messages by echo’ing them out.

Conclusion

PHP 7 is looking great. There are quite a few other new features that I haven’t covered in this article, but I encourage you to take a look. This would include changes in how errors are handled, unicode codepoints, changes to the use keyword, generator return expressions and delegation, integer division and more. I, for one, cannot wait to start using it in real production applications.

You can start playing with PHP 7 right now as well. Rasmus Lerdorf, the creator of PHP, has released a Vagrant VM which allows you to easily build and switch between different versions of PHP. The link is in the requirements box at the start of this article. You can test your own code in there or use the VM to play around with the new PHP 7 features. If you find bugs or issues, please be sure to report them to PHP’s bug tracker. Testing your code on PHP 7 and reporting any problems you find will help to make PHP 7 amazing for everyone.