What to Expect When You’re Expecting: PHP 7, Part 1
As many of you are probably aware, the RFC I mentioned in my PHP 5.0.0 timeline passed with PHP 7 being the agreed upon name for the next major version of PHP.
Regardless of your feelings on this topic, PHP 7 is a thing, and it’s coming this year! With the RFC for the PHP 7.0 Timeline passing almost unanimously (32 to 2), we have now entered into feature freeze, and we’ll see the first release candidate (RC) appearing in mid June.
But what does this mean for you? We have seen a huge reluctance of web hosts to move towards newer versions of 5.x. Won’t a major version bring huge backwards compatibility breaks and make that move even slower?
The answer to that is: it depends. So keep reading.
A number of language edge cases have been cleaned up. Additionally, both performance and inconsistency fixes have been major focuses for this release.
Let’s get into the details.
Inconsistency Fixes
Unfortunately, the needle/haystack issues have not been fixed. However, two major RFCs have passed that will bring some much-needed internal and userland consistency.
The largest (and most invisible) is the addition of an Abstract Syntax Tree (AST) — an intermediate representation of the code during compilation. With this in place, we are able to clean up some edge case inconsistencies, as well as pave the way for some amazing tooling in the future, such as using the AST to produce more performant opcodes.
The second, which is the introduction of Uniform Variable Syntax, may cause you more issues. This solves numerous inconsistencies in how expressions are evaluated. For example, the ability to call closures assigned to properties using ($object->closureProperty)()
, as well as being able to chain static calls, like so:
class foo { static $bar = 'baz'; }
class baz { static $bat = 'Hello World'; }
baz::$bat = function () { echo "Hello World"; };
$foo = 'foo';
($foo::$bar::$bat)();
However, some semantics are also changing. In particular, the semantics when using variable-variables/properties.
Prior to PHP 7, $obj->$properties['name']
would access the property whose name is in the name key of the $properties
array. With Universal Variable Syntax, it would access the name key of the property whose name resides in $properties.
Or to be more concise, if we take this statement:
$obj->$properties['name']
In PHP5.6, it would be interpreted as:
$obj->{$properties['name']}
And in PHP 7 as:
{$obj->$properties}['name']
While the use of variable-variables is generally an edge-case, and frowned upon, variable-properties are much less uncommon in my experience. You can, however, easily work around this with the application of curly braces (as in the illustration above) to ensure the same behavior in PHP 5.6 and 7.
Performance
The biggest reason for upgrading to PHP 7 is it’s performance, brought primarily with the changes introduced as phpng. The performance increases may in fact ensure quick adoption, especially from smaller hosts who would normally not do so, as they will be able to host more customers on the same hardware.
As things currently stand, depending on whose benchmark you see, the performance of PHP 7 is on par with Facebooks HHVM, which features a Just In Time (JIT) compiler that compiles PHP code all the way down to machine instructions (if it is able).
PHP 7 does not feature a JIT, though it has been discussed a lot. It is unclear if there are more performance gains to be had with the addition of one, but it sure will be interesting to see if someone decides to create one!
In addition to performance, there should be substantial memory savings, as optimization of internal data structures is one of the primary ways in which performance improvements have been achieved.
Backwards Incompatible Changes
While the internals developers have tried very hard not to break Backwards Compatibility (BC) it is not always possible to do so while moving the language forward.
However, like the BC breaks introduced with Uniform Variable Syntax, most of them are minor, such as the catchable fatal errors when trying to call a method on a non-object:
set_error_handler(function($code, $message) {
var_dump($code, $message);
});
$var = null;
$var->method();
echo $e->getMessage(); // Fatal Error: Call to a member function method() on null
echo "Hello World"; // Still runs
Additionally ASP and script tags have been removed, meaning you can no longer use <% and <%=, or <script language=”php”> (and their respective close tags, %>, and </script>).
Other much larger changes however are to be found in the removal of all deprecated functionality.
Most importantly, the removal of the POSIX compatible regular expressions extension, ext/ereg (deprecated in 5.3) and the old ext/mysql extension (deprecated in 5.5).
One other minor BC breaking change is disallowing multiple default cases in a switch. Prior to PHP 7, the following was allowed:
switch ($expr) {
default:
echo "Hello World";
break;
default:
echo "Goodbye Moon!";
break;
}
This would result in only the latter being executed. In PHP 7, this will result in:
Fatal error: Switch statements may only contain one default clause
New Features
We begrudgingly deal with the effects of backwards incompatibility. We appreciate performance. But we revel in new features! New features are what make each release fun — and PHP 7 is not short on new features.
Scalar Type Hints & Return Types
I’m going to start with the most controversial change that was added for PHP 7: Scalar Type Hints. The addition of this feature involved vote that almost passed. But then the author left PHP developement for good (withdrawing the RFC). This was then followed by multiple RFCs for competing implementations, and a whole lot of public fighting that ultimately ended with (effectively) the original RFC being passed.
For you, as end-users, what this means is that you can now type-hint with scalar types. Specifically: int, float, string, and bool. By default type-hints are non-strict, which means they will coerce the original type to the type specified by the type-hint. This means if you pass int(1)
into a function that requires a float, it will be come float(1.0)
. Passing float(1.5)
into a function that requires an int, it will be come int(1)
.
Here’s an example:
function sendHttpStatus(int $statusCode, string $message) {
header('HTTP/1.0 ' .$statusCode. ' ' .$message);
}
sendHttpStatus(404, "File Not Found"); // integer and string passed
sendHttpStatus("403", "OK"); // string "403" coerced to int(403)
Additionally, you can enable strict mode by placing declare(strict_types=1);
at the top of any given file will ensure that any function calls made in that file strictly adhere to the types specified. Strict is determined by the file in which the call to a function is made, not the file in which the function is defined.
If a type-hint mismatch occurs, a Catchable Fatal Error is thrown:
<?php
declare(strict_types=1); // must be the first line
sendHttpStatus(404, "File Not Found"); // integer and string passed
sendHttpStatus("403", "OK");
// Catchable fatal error: Argument 1 passed to sendHttpStatus() must be of the type integer, string given
Furthermore, PHP 7 also supports Return Type Hints which support all the same types as arguments. These follow the same syntax as hack, suffixing the argument parenthesis with a colon followed by the type:
function isValidStatusCode(int $statusCode): bool {
return isset($this->statuses[$statusCode]);
}
In this example the : bool
indicates that the function will return a boolean.
The same rules that apply to type-hints apply to returned type hints for strict mode.
Combined Comparison Operator
My personal favorite addition to PHP 7 is the addition of the Combined Comparison Operator, <=>
,otherwise known as the spaceship operator. I might be biased, as I wrote the initial patch and influenced the naming (T_SPACESHIP
), but this operator is still a nice addition to the language, complementing the greater-than and less-than operators.
It effectively works like strcmp()
, or version_compare()
, returning -1 if the left operand is smaller than the right, 0 if they are equal, and 1 if the left is greater than the right. The major difference being that it can be used on any two operands, not just strings, but also integers, floats, arrays, etc.
The most common usage for this operator is in sorting callbacks:
// Pre Spacefaring^W PHP 7
function order_func($a, $b) {
return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}
// Post PHP 7
function order_func($a, $b) {
return $a <=> $b;
}
Next Up
In this post, we’ve taken a look at the some of the most important inconsistency fixes coming up in PHP 7 and we’ve looked at the two of the biggest new features.
In the next post in this two part series, we’ll take a look at six other big features coming in PHP 7 that you’ll want to know about. Plus, we’ll round off the series by looking at some of the ways *you *can get involved in helping with the PHP 7 effort.
P.S. While you’re waiting, why don’t you share some of the things you’re most looking forward to in PHP 7? Or maybe some of the stuff you’re disappointed won’t be making it.
Share your thoughts with @engineyard on Twitter
OR
Talk about it on reddit