New language features in PHP 7
last modified July 13, 2020
In this article, we present new language features of PHP 7. The article focuses on the features of the core language. For our examples, we use PHP CLI. PHP tutorial is a concise tutorial of PHP language on ZetCode. In the PHP filesystem functions article, we cover numerous PHP functions related to filesystem.
Between years 2014 and 2015, a new major PHP version was developed, which was numbered PHP 7. After some debate among developers, version 6 was skipped in order to avoid confusion with PHP Unicode experiment, which was referred to as PHP 6 in the press. First, we are going to show how to install PHP 7 from the sources.
Installing PHP
We download PHP from the http://php.net/downloads.php
page. We have downloaded php-7.0.4.tar.bz2
file.
$ bunzip2 php-7.0.4.tar.bz2 $ tar -xf php-7.0.4.tar $ cd php-7.0.4/
We decompress the file and move into the build directory.
$ sudo apt-get install libreadline-dev $ sudo apt-get install libicu-dev
We need to install readline development library for PHP interactive shell and the development files for international components for Unicode.
$ ./configure --with-readline --enable-intl
We run the configure
script with readline and internationalization
support enabled.
$ make $ sudo make install
We build and install PHP. It is possible that we need to install some additional
packages. For instance, the author had to install libxml2-dev
library.
$ sudo cp php.ini-development /usr/local/lib/php.ini $ sudo ln -s /usr/local/lib/php.ini /etc
We copy the php.ini
file and make a link to it in the /etc
directory.
$ php -a Interactive shell php > echo PHP_VERSION; 7.0.4
We run PHP in interactive mode and get the version of PHP.
Integer division
The division operator (/) returns a float point value. The
divint()
function performs integer division.
The first parameter is the dividend, the second parameter
is the divisor.
<?php echo 7/3, "\n"; echo intdiv(7, 3), "\n"; ?>
The example prints values of a floating point and integer divisions.
$ php integer_division.php 2.3333333333333 2
This is the output of the integer_division.php
program.
The spaceship operator
The spaceship operator (<=>), also known as combined comparison operator,
can be used to make chained comparisons more concise. In behaviour, it is similar to
to strcmp()
or version_compare()
.
$a <=> $b
This expression evaluates to -1 if $a
is smaller than $b
,
0 if $a
equals $b
, and 1 if $a
is greater than
$b
.
($a < $b) ? -1 : (($a > $b) ? 1 : 0)
The expression is rewritten without the spaceship operator.
<?php echo 1 <=> 1; // 0 echo 1 <=> 2; // -1 echo 2 <=> 1; // 1 echo "\n"; echo "a" <=> "a"; // 0 echo "a" <=> "b"; // -1 echo "b" <=> "a"; // 1 echo "\n"; echo [] <=> []; // 0 echo [1, 2, 3] <=> [1, 2, 3]; // 0 echo [1, 2, 3] <=> []; // 1 echo [1, 2, 3] <=> [1, 2, 1]; // 1 echo [1, 2, 3] <=> [1, 2, 4]; // -1 echo "\n"; ?>
The example uses the spaceship operator on numbers, strings, and arrays.
echo 1 <=> 1; // 0
Numbers are compared by their size.
echo "a" <=> "b"; // -1
Strings are compared lexically; e.i. by their alphabetical order.
echo [1, 2, 3] <=> [1, 2, 1]; // 1
In case of arrays, corresponding array elements are compared with one another.
$ php spaceship_operator.php 0-11 0-11 0011-1
This is the output of the spaceship_operator.php
program.
The null coalescing operator
The null coalescing operator (??) is a syntactic sugar for the common
case of having to use a ternary operator in conjunction with isset()
. It returns
its first operand if it exists and is not NULL
; otherwise it returns its
second operand.
php > $mycolour = $colour ?? "blue"; php > echo $mycolour; blue
Since the $colour
variable is not defined, the ??
operator
returns its second operand.
php > $mycolour = isset($colour) ? $colour : "blue"; php > echo $mycolour; blue
In previous versions of PHP, we would need to used the isset()
function.
Scalar type declarations
Scalar type declarations are type hints for function parameters. There are two types
of declarations: coercive (default) and strict. The following types for parameters can
now be enforced string
, int
, float
,
and bool
.
The types are enforced with the declare()
function.
<?php // declare(strict_types=1); function add(int $a, int $b) { return $a + $b; } $r = add(4, 6); echo "$r\n"; $r = add("4", "6"); echo "$r\n"; ?>
In the coercive mode, the example prints 10 for both cases. If we enable
the strict mode by removing the comment, we receive the following error
message: Fatal error: Uncaught TypeError: Argument 1 passed to add()
must be of the type integer, string given
.
Return type declarations
The return type declarations specify the type of the value that is returned from a function. The same types are available for return type declarations as are available for argument type declarations.
<?php declare(strict_types=1); function add( $a, $b) : int { return $a + $b; } $r = add(4, 6.0); echo "$r\n"; ?>
The function has an int
return type declared. We pass
a floating point value to the function which results in a float return
value. The program ends with this error: Fatal error: Uncaught TypeError:
Return value of add() must be of the type integer, float returned
.
Unicode codepoint escape syntax
The syntax takes a codepoint in hexadecimal form and outputs that codepoint in UTF-8 to a double-quoted string or a heredoc. Any valid codepoint is accepted, with leading 0's being optional. (Code points are numerical values that represent a character.)
<?php echo "\u{13C7}", "\n"; echo "\u{1307}", "\n"; ?>
The example prints a Cherokee letter que and ethiopic syllable jwa.
$ php unicode_codepoints.php Ꮗ ጇ
This is the output of the unicode_codepoints.php
program.
IntlChar class
The new IntlChar
class provides access to a number of utility
methods that can be used to access information about Unicode characters.
<?php echo IntlChar::charName('Ꮗ'), "\n"; echo IntlChar::charName('ጇ'), "\n"; ?>
The example uses the IntlChar::charName()
function to
retrieve the name of two Unicode characters.
$ php intlcharex.php CHEROKEE LETTER QUE ETHIOPIC SYLLABLE JWA
This is the output of the intlcharex.php
script.
Anonymous classes
Anonymous classes are classes that do not have a name. They are useful when simple, one-off objects need to be created.
<?php $c = new class { public function say() { echo "This is an anonymous class\n"; } }; $c->say(); ?>
We assign an object to the $c
variable; the object
is created from a class that does not have a name.
$ php anonymous_class.php This is an anonymous class
This is the output of the anonymous_class.php
script.
Expectations
Expectations are backwards compatible enhancement to the older assert()
function. It is possible to have zero-cost assertions in production code and
to provide the ability to throw custom exceptions when the assertion fails.
The zend.assertions
configuration setting can have one of three values:
- 1 — generate and execute code (development mode)
- 0 — generate code and jump around at it at runtime
- -1 — don't generate any code (zero-cost, production mode)
The assert.exception
sets whether an exception is thrown when an
assertion fails. This is switched off by default to remain compatible with the
old assert()
function.
<?php abstract class Grades { const A = 0; const B = 1; const C = 2; const D = 3; const E = 4; const FX = 5; } const G = 6; //$grade = Grades::A; $grade = G; switch ($grade) { case Grades::A: echo "Outstanding\n"; break; case Grades::B: echo "Superior\n"; break; case Grades::C: echo "Good\n"; break; case Grades::D: echo "Satisfactory\n"; break; case Grades::E: echo "Low pass\n"; break; case Grades::FX: echo "Failure\n"; break; default: assert (false, "Unrecognized grade passed through switch: {$grade}"); } echo "code continues\n"; ?>
We have a system of college grades.
//$grade = Grades::A; $grade = G;
A wrong value is given to the $grade
variable.
default: assert (false, "Unrecognized grade passed through switch: {$grade}");
We place an assertion at a location we assume will not be reached.
$ php expectations.php Warning: assert(): Unrecognized grade passed through switch: 6 failed in /home/janbodnar/prog/php7/expectations.php on line 44 code continues
The script contains the above warning, but it continues.
ini_set('assert.exception', 1);
It is possible to enable exceptions by setting the assert.exception
configuration. This time the script fails with Fatal error: Uncaught AssertionError:
Unrecognized suit passed through switch: 6
.
The levels paramter of dirname()
The dirname()
function returns the parent's directory path.
The new levels
parameter tells how many parent directories
to go up.
<?php echo dirname('/usr/local/bin').PHP_EOL; echo dirname('/usr/local/bin', 1).PHP_EOL; echo dirname('/usr/local/bin', 2).PHP_EOL; echo dirname('/usr/local/bin', 3).PHP_EOL; ?>
In the script, we utilize the new optional parameter of
the dirname()
function.
$ php dirlevels.php /usr/local /usr/local /usr /
This is the output of the dirlevels.php
script.
Array constants in define()
Since PHP 5.6 it is possible to define constant arrays with the const
keyword.
In PHP 7, a constant array can be created with define()
too.
<?php const POSSIBLE_GRADES = ['A', 'B', 'C', 'D', 'E', 'FX']; define('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']); print_r(POSSIBLE_GRADES); print_r(ALLOWED_IMAGE_EXTENSIONS); ?>
The code example creates two array constants; one with the const
keyword
and one with the define()
function.
$ php array_constants.php Array ( [0] => A [1] => B [2] => C [3] => D [4] => E [5] => FX ) Array ( [0] => jpg [1] => jpeg [2] => gif [3] => png )
This is the output of the array_constants.php
script.
New use syntax
The use
keyword allows to group multiple declarations in
one statement.
<?php namespace ZetCode; class Night { function say() { echo "This is Night class\n"; } } class Day { function say() { echo "This is Day class\n"; } } function f1() { echo "This is f1()\n"; } function f2() { echo "This is f2()\n"; } ?>
In the myfile.php
we have two classes and two functions defined
in a ZetCode
namespace.
<?php include 'myfile.php'; use ZetCode\{Day, Night}; use function ZetCode\{f1, f2}; $d = new Day(); $d->say(); $n = new Night(); $n->say(); f1(); f2(); ?>
In the usegroup.php
we use the classes and functions from
ZetCode
namespace.
use ZetCode\{Day, Night}; use function ZetCode\{f1, f2};
The new syntax of use
allows to import several declarations
in one statement.
use ZetCode\Day; use ZetCode\Night; use function ZetCode\f1; use function ZetCode\f2;
This is the syntax for previous versions of PHP.
$ php usegroup.php This is Day class This is Night class This is f1() This is f2()
This is the output.
Closure call() method
PHP 5.4 added the ability to bind closures to an object's scope.
This process is simplyfied in PHP 7 with the call()
method.
<?php class Greeting { private $word = "Hello"; } $f = function($whom) { echo "$this->word $whom\n"; }; $obj = new Greeting(); $f->call($obj, 'Tom'); $f->call($obj, 'Jane'); ?>
With a closure, we access a private variable of a class.
$ php closure_call.php Hello Tom Hello Jane
This is the output of the closure_call.php
script.
Generator return expressions
A return
statement can be used within a generator to enable
for a final expression to be returned. This value can be retrieved with
the getReturn()
method, which may only be used once the generator
has finishing yielding values.
<?php srand(); function random_numbers($k) { for ($i=0; $i<$k; $i++) { $r = rand(1, 10); yield $r; } return -1; } $rns = random_numbers(10); foreach ($rns as $r) { echo "$r\n"; } echo $rns->getReturn() . PHP_EOL; ?>
Our generator returns random values. At the end of the iteration, the generator returns -1.
$ php generator_return.php 7 5 6 7 1 1 9 6 5 8 -1
This is a sample output of the generator_return.php
script.
Generator delegation via yield from
Generator delegation allows to yield values from another generator,
Traversable
object, or array by using the yield from
keyword. Generator delegation promotes cleaner code and reusability.
<?php function f1() { yield from f2(); yield "f1() 1"; yield "f1() 2"; yield from [3, 4]; yield "f1() 3"; yield "f1() end"; } function f2() { yield "f2() 1"; yield "f2() 2"; yield "f2() 3"; yield "f2() end"; } $f = f1(); foreach ($f as $val) { echo "$val\n"; } ?>
In the example, we yield values another generator and an array.
function f1() { yield from f2(); ...
Values are yield from f2()
generator.
yield from [3, 4];
It is also possible to yield values from an array.
$ php generator_delegation.php f2() 1 f2() 2 f2() 3 f2() end f1() 1 f1() 2 3 4 f1() 3 f1() end
This is the output of the generator_delegation.php
script.
Uniform variable syntax
New uniform variable syntax allows combinations of operators that were previously disallowed; old operations can be achieved in terser code. The new syntax always follows a left-to-right evaluation order. The uniform variable syntax breaks backward compatibility in some expressions where old evaluation is used.
<?php function e() { echo "This is e() \n"; }; function f() { echo "This is f() \n"; return e; }; function g() { echo "This is g()\n"; return f; }; g(); echo "***********\n"; g()(); echo "***********\n"; g()()(); ?>
The example uses g()()
and g()()()
, which were not
possible in earlier PHP versions.
g();
Here the g()
function is executed.
g()();
This statement executes the g()
function and the return
of the g()
function.
g()()();
The g()
function is executed, the return of the
g()
function is executed, and the return of the return
is executed.
$ php uniform_variable_syntax.php This is g() *********** This is g() This is f() *********** This is g() This is f() This is e()
This is the output of the uniform_variable_syntax.php
script.
The following is another example of a new syntax introduced with the uniform variable syntax.
<?php class A { function f() { echo "f() of A\n"; } } class B { function g() { echo "g() of B\n"; return new A(); } } $b = new B(); $b->g()::f(); ?>
The $b->g()::f()
executes an f()
method of a
class A
returned by method g()
.
$ php uniform_variable_syntax2.php g() of B f() of A
This is the output of the uniform_variable_syntax2.php
script.
In the third example, we have an immediately-invoked function expression, which is a term from the JavaScript language.
<?php $v = (function() { return 11 - 5; })(); echo "$v\n"; ?>
Immediately-invoked function expression is an anonymous function that is executed right after it is created.
$ php uniform_variable_syntax3.php 6
This is the output of the uniform_variable_syntax3.php
script.
Changes in exceptions and errors
In PHP 7, an exception is thrown when a fatal and recoverable error (E_ERROR
and E_RECOVERABLE_ERROR
) occurs, rather than halting script execution. These
fatal and recoverable errors are now instances of a new and separate exception class:
Error
. Some errors throw a more concrete error: TypeError
,
ParseError
, ArithmeticError
, and AssertionError
.
Other types of errors such as warnings and notices remain unchanged in PHP 7. Only fatal and recoverable errors throw exceptions.
A new Throwable
interface is introduced to unite the two exception branches:
Exception
and Error
; they both implement the Throwable
.
<?php class A { public function say() { echo "This is class A\n"; } } try { $a = new A(); $a->say(); $a = null; $a->say(); } catch (Error $e) { echo "Error occured" . PHP_EOL; echo $e->getMessage() . PHP_EOL ; echo "File: " . $e->getFile() . PHP_EOL; echo "Line: " . $e->getLine(). PHP_EOL; } echo "Script continues\n"; ?>
In the example, we call a method on null
object.
We catch the exception and handle it; the script then continues.
$ php null_error.php This is class A Error occured Call to a member function say() on null File: /home/janbodnar/prog/php7/null_error.php Line: 17
This is the output of the null_error.php
script.
DivisionByZeroError
is an ArithmeticError
which
is thrown from intdiv()
and the modulo (%) operator when the
denominator is zero. The (\) division operator issues still
a Warning: Division by zero
warning.
<?php $a = 4; $b = 0; try { $c = intdiv($a , $b); } catch (DivisionByZeroError $e) { echo "Error occured\n"; echo $e->getMessage() . PHP_EOL ; echo "File: " . $e->getFile() . PHP_EOL; echo "Line: " . $e->getLine(). PHP_EOL; } echo "$c \n"; echo "Script continues\n"; ?>
In the example, we catch and report a DivisionByZeroError
in a intdiv()
function.
$ php arithmetic_error.php Error occured Division by zero File: /home/janbodnar/prog/php7/arithmetic_error.php Line: 8 Script continues
This is the output of the arithmetic_error.php
script.
Sources
The following sources were used to create this article:
In this article, we have presented new features of PHP 7 language. You may want to look at PHP tutorial now.