One of the most exciting events in 2015 in the PHP world was the release of PHP 7, 10 years on from the release of the last major version, PHP 5. With a major step forward, PHP 7 introduces plenty of new features and performance upgrades.
However, it also removes old, deprecated functionality, which introduces some compatibility breaks, making it harder for older applications to migrate to the new version. This guide should serve as a quick tour on what to expect if you plan on moving your existing applications, or building new ones, on top of PHP 7.
But Wait, Where Did PHP 6 Go?
If you haven’t been working with PHP lately, you might wonder what happened to PHP 6, why the skip from PHP 5 to PHP 7? Well, long story short, PHP 6 was a failure. The main feature of version 6 was native support for Unicode characters since PHP is used mainly in web development and the web needs Unicode, so the move to bring Unicode to PHP made sense.
The idea was to bring complete support for Unicode to the core itself. It would have brought extended capabilities to the language, from the ability to use silly emojis as variable and function names, to powerful international string functionality. For instance, when another language uses upper and lower case letters differently from English, or when a name in Chinese characters needs to be converted to English.
PHP 6 was ambitious, but rubbish. That’s how we ended up with PHP 7, skipping version 6 in the process.
Unfortunately, this ambitious plan proved to be a bigger problem than anticipated. Much of the codebase had to be ported to support Unicode for both core and important extensions, which proved tedious and tricky. This slowed down development of other features in the language, frustrating many PHP developers in the process. Additional hurdles showed up, which resulted in less interest in developing a native Unicode support, ultimately leading to the project being abandoned.
Since resources, such as books and articles, had been written for PHP 6 and its Unicode support, the new version would be renamed PHP 7 to avoid confusion.
Anyway, enough dwelling in the sad past, let’s see what PHP 7 brings to the party.
Performance Battle, PHP 7 vs. PHP 5
With virtually all updates, minor performance upgrades are to be expected. However, this time PHP brings a significant improvement over earlier versions making sheer performance one of PHP 7’s most attractive features. This comes as part of the “PHPNG” project, which tackles the internals of the Zend Engine itself.
By refactoring internal data structures and adding an intermediate step to code compilation in the form of an Abstract Syntax Tree (AST), the result is superior performance and more efficient memory allocation. The numbers themselves look very promising; benchmarks done on real world apps show that PHP 7 is twice as fast as PHP 5.6 on average, and results in 50 percent less memory consumption during requests, making PHP 7 a strong rival for Facebook’s HHVM JIT compiler. Have a look at this infographic from Zend depicting performance for some common CMS and Frameworks.
The decrease in memory consumption also allows smaller machines to handle requests better along with the opportunity for building micro services around PHP. The internal changes, in particular the AST implementation, also opens possibilities for future optimisations that could push performance even further. A new, in-house implementation of a JIT compiler is being considered for future versions.
PHP 7 Syntactic Sugar
PHP 7 comes with new syntax features. While not extending the capabilities of the language itself, they provide a better, or easier, way of making your code more enjoyable to write and pleasing to the eye.
Group Import Declarations
Now, we can group import declarations for classes originating from the same namespace into a single use line. This should help aligning declarations in a meaningful way or simply save some bytes in your files.
use Framework\Module\Foo;
use Framework\Module\Bar;
use Framework\Module\Baz;
With PHP 7 we can use:
use Framework\Module\{Foo, Bar, Baz};
Or, if you prefer a multi-line style:
use Framework\Module{
Foo,
Bar,
Baz
};
Null Coalescing Operator
This solves a common problem in PHP programming, where we want to assign a value to a variable from another variable, if the latter is actually set, or otherwise provide a different value for it. It’s commonly used when we work with user-provided input.
Pre-PHP 7:
if (isset($foo)) {
$bar = $foo;
} else {
$bar = ‘default’; // we would give $bar the value ‘default’ if $foo is NULL
}
After PHP 7:
$bar = $foo ?? ‘default’;
This can be also chained with a number of variables:
$bar = $foo ?? $baz ?? ‘default’;
Spaceship Operator
The spaceship operator allows for a three way comparison between two values, not only indicating if they are equal, but also which one is bigger, on inequality by returning 1,0 or -1.
Here we can take different actions depending on how the values differ:
switch ($bar $foo) {
case 0:
echo ‘$bar and $foo are equal’;
case -1:
echo ‘$foo is bigger’;
case 1:
echo ‘$bar is bigger’;
}
The values compared can be integers, floats, strings or even arrays. Check the documentation to get an idea of how different values are compared to each other. [https://wiki.php.net/rfc/combined-comparison-operator]
New Features In PHP 7
But of course PHP 7 also brings new and exciting functionality with it.
Scalar Parameter Types & Return Type Hints
PHP 7 extends the previous type declarations of parameters in methods ( classes, interfaces and arrays) by adding the four scalar types; Integers (int), floats (float), booleans (bool) and strings (string) as possible parameter types.
Further, we can optionally specify what type methods and functions return. Supported types are bool, int, float, string, array, callable, name of Class or Interface, self and parent ( for class methods )
class Calculator
{
// We declare that the parameters provided are of type integer
public function addTwoInts(int $x, int $y): int {
return $x + $y; // We also explicitly say that this method will return an integer
}
}
Type declarations allow the building of more robust applications and avoid passing and returning wrong values from functions. Other benefits include static code analyzers and IDEs, which provide better insight on the codebase if there are missing DocBlocks.
Since PHP is a weakly typed language, certain values for parameter and return types will be cast based on the context. If we pass the value “3” in a function that has a declared parameter of type int, the interpreter will accept it as an integer and not throw any errors. If you don’t want this, you can enable strict mode by adding a declare directive.
declare(strict_types=1);
This is set in a per-file basis, as a global option would divide code repositories to those that are built with global strictness on and those that are not, resulting in unexpected behavior when we combine code from both.
Engine Exceptions
With the addition of engine exceptions, fatal errors that would have resulted in script termination can be caught and handled easily.
Errors such as calling a nonexistent method won’t terminate the script, instead they throw an exception that can be handled by a try catch block, which improves error handling for your applications. This is important for certain types of apps, servers and daemons because fatal errors would otherwise require them to restart. Tests in PHPUnit should also become more usable as fatal errors drop the whole test suite. Exceptions, rather than errors, would be handled on a per test case basis.
PHP 7 adds a number of new exception classes based on the type of errors that might be encountered. In order to maintain compatibility between versions, a new Throwable interface has been added that can be implemented from both engine exceptions and user exceptions. This was necessary in order to avoid engine exceptions to extend the base exception class, resulting in older code- catching exceptions that were not there before.
Before PHP 7 this would have terminated the script with a fatal error:
try {
thisFunctionDoesNotEvenExist();
} catch (\EngineException $e) {
// Clean things up and log error
echo $e->getMessage();
}
Anonymous Classes
Anonymous classes are cousins of anonymous functions that you might use in a simple short-term instance. Anonymous classes are easily created and used just like a regular object. Here is an example from the docs.
Pre-PHP 7
class MyLogger {
public function log($msg) {
print_r($msg . “\n”);
}
}
$pusher->setLogger( new MyLogger() );
With anonymous class:
$pusher->setLogger(new class {
public function log($msg) {
print_r($msg . “\n”);
}
});
Anonymous classes are useful in unit testing, particularly in mocking test objects and services. This helps us avoid heavy mocking libraries and frameworks by creating a simple object that provides the interface we want to mock.
CSPRNG Functions
Two new functions for generating cryptographically secure string and integers were added.
random_bytes(int $len);
Returns a random string with length $len.
random_int(int $min, int $max);
Returns a number between $min and $max.
Unicode Codepoint Escape Syntax
Unlike many other languages, prior to PHP 7, PHP did not have a way to escape a Unicode codepoint in string literals, . This functionality adds the escape \u sequence to produce such characters using their UTF-8 codepoint. This is better than inserting the characters directly, allowing better handling of invisible characters as well as characters that have the same graphical representation but differ in meaning.
echo “\u{1F602}”; // outputs 😂‚
Note that this breaks existing code with the \u sequence because it changes the behaviour.
Generators Get Upgraded
Generators in PHP get also some nice additional features. Now, generators have a return statement that can be used to allow it to output a final value following the iteration. This can used to check that the generator has been executed without errors and allows the code that called the generator to handle various scenarios appropriately.
Further, generators can return and yield expressions from other generators. This allows them to divide complex operations to simpler and modular units.
function genA() {
yield 2;
yield 3;
yield 4;
}
function genB() {
yield 1;
yield from genA(); // ‘genA’ gets called here and iterated over
yield 5;
return ‘success’; // This is a final result we can check later
}
foreach (genB() as $val) {
echo “\n $val”; // This will output values 1 to 5 in order
}
$genB()->getReturn(); // This should return ‘success’ when there are no errors.
Expectations
Expectations are an enhancement to the assert() function while maintaining backward compatibility. They allow for zero-cost assertions in production code, and provide the ability to throw custom exceptions when the assertion fails, which can be useful during development.
assert() becomes a language construct in PHP 7. Assertions should be used for debugging purposes only in developing and testing environments. To configure its behaviour, we are provided with two new directives.
zend.assertions
1: generate and execute code (development mode) (default value)
0: generates the code but jumps around it at runtime
-1: does not generate code making it zero-cost (production mode)
assert.exception
1: throw when the assertion fails, either by throwing the object provided as the exception or by throwing a new AssertionError object if exception wasn’t provided
0: use or generate a Throwable as described above, but only generate a warning based on that object rather than throwing it (compatible with PHP 5 behaviour)
Preparing to move from PHP 5 to PHP 7
The introduction of a major release brings an opportunity to change/update older functionalities or even remove them if they are deemed too old or have been deprecated for some time. Such changes can introduce breaks in compatibility in older applications.
Another issue that arises from such version leaps is that important libraries and frameworks that you depend upon may have not yet have been updated to support the latest version. The PHP team has tried to make the new changes as backward-compatible as possible and allow migration to the new version to be as painless as possible. Newer and more up-to-date apps should find it easier to move to the new version, whereas older apps may have to decide if the benefits outweigh the cost, possibly choosing to not update.
Most breaks are minor and can be mitigated easily while others may require more effort and time. Basically, if you had deprecation warnings in your application before installing PHP 7 you will probably get errors that will break the application until fixed. You were warned, right?
Old SAPIs and Extensions
Most importantly, old and deprecated SAPIs were removed like the mysql extension (but you should not be using this in the first place, right?). For a full list of extensions and featured removed you can check this RFCs here and here.
Additionally, other SAPIs are being ported to PHP 7.
Uniform Variable Syntax
This update made some changes in favour of consistency for variable-variable constructions. This allows for more advanced expressions with variables but introduces changes in behaviour in some other cases, as shown below.
// old meaning // new meaning
$$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’]()
This would break the behaviour of applications accessing values like this. On the other hand, you can do some neat stuff like this:.
// Nested ()
foo()(); // Calls the return of foo()
$foo->bar()();
// IIFE syntax like JavaScript
(function() {
// Function body
})();
// Nested ::
$foo::$bar::$baz
Old Style Tags Removed
The opening/closing tags , , … are removed and not valid anymore. Replacing them with the valid ones should be easy, but what are you doing using them anyway, Weirdo?
Invalid Names for Classes, Interfaces and Traits
Resulting from additions such as parameter and return types classes, interfaces and traits are no longer allowed to have the following names:
bool
int
float
string
null
true
false
These cause breaks to existing applications and libraries that use them, but they should be easy to fix. Also, although they don’t cause any error and are valid, the following should not be used as they are reserved for future use:
resource
object
mixed
numeric
Refraining from using them should spare you the work of changing them in the future.
For a full list of changes that would break compatibility, check this document.
You can also use php7cc, which checks your code and can detect any potential issues that may emerge if you move to PHP 7. But of course, there is no better way than installing PHP 7 and seeing for yourself.
Potential PHP 7 Compatibility Issues
PHP 7 Infrastructure Compatibility
A lot of hosting services have started to add support for PHP 7. This is good news for shared hosting providers, as the performance gains will allow them to increase the number of client websites on their hardware, reducing their operating expenses and boosting their margins. As for the clients themselves, they should not expect too much of a boost under these conditions, but to be fair, shared hosting is not a performance-oriented choice anyway.
On the other hand, services that offer virtual private servers or dedicated servers will reap the full benefits of this performance bump. Some PaaS services like Heroku supported PHP 7 early on, but other services, like AWS Beanstalk and Oracle’s OpenShift, are lagging behind. Check your PaaS provider’s website to see if PHP 7 is already supported, or if support is coming in the near future.
Of course, IaaS providers allow you to take control of the hardware and install PHP 7 (or compile if that is more to your liking). PHP 7 packages are already available for major IaaS environments.
PHP 7 Software Compatibility
In addition to infrastructure compatibility, you also need to be mindful of potential software compatibility issues. Popular content management systems like WordPress, Joomla, and Drupal have added support for PHP 7 with their latest releases. Major frameworks like Symfony and Laravel also enjoy full support.
However, it’s time for a word of caution. This support does not extend to third-party code in the form of add-ons, plugins, packages, or whatever your CMS or framework calls them. They may suffer from compatibility issues and it’s your responsibility to make sure everything is ready for PHP 7.
For active, maintained repositories, this should not be an issue. However, older and unmaintained repositories lacking PHP 7 support could render your whole app unusable.
The future Of PHP
The release of PHP 7 removed old and obsolete code and paved the way for new features and performance upgrades in the future. Plus, PHP is expected to gain additional performance optimisations soon. Despite having some compatibility breaks with past releases, most of the issues are easy to resolve.
Libraries and frameworks are now migrating their code to PHP 7 thus making available the latest versions . I encourage you to try it out and see the results for yourself. Maybe your application is already compatible and waiting to use, and benefit from, PHP 7.
The original article was written by VILSON DUKA – FREELANCE SOFTWARE ENGINEER @ TOPTAL