BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles PHP 7 — Improvements to Arrays, Operators, Constants, and Exception Handling

PHP 7 — Improvements to Arrays, Operators, Constants, and Exception Handling

Key Takeaways

  • PHP 7.0 adds the null coalescing operator (??)  to return  the first operand   if it exists and its value is not NULL, and returns the second operand otherwise. PHP 7.4 adds support for null coalescing assignments. 
  • PHP 7.0 adds a new comparison operator (<=>) to compare expressions.
  • PHP 7.0 adds support for Unicode codepoint escape syntax, to convert an hexadecimal form to the corresponding UTF-8 encoded form. 
  • The use statement may group classes, functions, and constants even when imported from the same namespace.
  • PHP 7.1, adds a short form array syntax for unpacking or destructuring an array. 
  • PHP  7.1  adds support for class constant visibility, using which constants may be declared public, protected and private.
  • PHP 7 supports specifying multiple exceptions in the same catch block of a try/catch statement.
  • With PHP 7.0.0, keywords may be used as identifiers.
  • PHP 7.3  introduces flexible Heredoc and Nowdoc syntax for better readability.
  • PHP 7.3 adds support for reference assignments in array and list() destructuring.
     

PHP 7.x brings several improvements and new features that touch all aspects of the language, including better support for object oriented programming, extensions to classes and interfaces, improvements to the type system, error handling, and more. In this series of articles, we discuss new features across the various PHP 7.x versions.

 

In this final article on the series on new features in PHP 7.x, we shall discuss improvements to arrays, operators, constants, and exception handling.

Null Coalescing Operator

The isset function can be used to find out if a variable is set and not NULL. Typically you will use the PHP ternary operator  with isset as shown in the following example. Here, isset returns true if the GET request parameter name is set, in which case variable its value is assigned to variable $name, otherwise  $name is set to a constant string value:

$name = isset($_GET['name']) ? $_GET['name'] : 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";

The null coalescing operator (??), which has been added to PHP 7.0, can be used to streamline this kind of operations. Indeed, it will return its first operand if it exists and its value is not NULL, and return the second operand otherwise. The preceding example could be rewritten as follows using ??:

$name = $_GET['name'] ?? 'Deepak';

Null coalescing operators may be chained to return the first defined value:

$name = $_GET['name'] ?? $_POST['name'] ?? 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";

Now, create a script ternary.php including all of the following  examples:

<?php
$name = $_GET['name'] ?? 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
$name = isset($_GET['name']) ? $_GET['name'] : 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
$name = $_GET['name'] ?? $_POST['name'] ?? 'Deepak';
echo "Hello " . htmlspecialchars($name)."<br>";
?>

If you run the script with no request parameter, all examples will output the last value specified:

Hello Deepak
Hello Deepak
Hello Deepak

If you instead run the script supplying a request parameter, say name=JohnSmith, all examples will output the request parameter received in  $_GET['name']:

Hello JohnSmith
Hello JohnSmith
Hello JohnSmith

New Comparison Operator

A new comparison operator (<=>) has been added to PHP 7.0  which returns -1 if the first expression is less than the second, 0 if the two expressions are the same, and 1 if the first expression is greater than the second.  PHP’s type comparison rules are used for performing the comparison. To demonstrate this, create a script compare.php to compare integer, floating-point and string values:

<?php
// Integers
echo 1 <=> 1; 
echo "<br>";
echo 1 <=> 0; 
echo "<br>";
echo 5 <=> 10; 
echo "<br>";
// Floats
echo 1.0 <=> 1.5;
echo "<br>";
echo 1.0 <=> 1.0; 
echo "<br>";
echo 0 <=> 1.0; 
echo "<br>";
// Strings
echo "a" <=> "a";
echo "<br>";
echo "a" <=> "c"; 
echo "<br>";
echo "c" <=> "a";
echo "<br>";
?>

If you run the script, you will  get the following comparison results:

0
1
-1
-1
0
-1
0
-1
1

Unicode codepoint Conversion from Hexadecimal Form to UTF-8

PHP 7.0 has added support for Unicode codepoint escape syntax, which takes an hexadecimal form and returns the corresponding UTF-8 encoded form.  For example, Ē is represented with U+0112 in Unicode, where  the leading 0 may be omitted. To experiment with  the Unicode codepoint escape syntax, create a script unicode.php. Copy the following listing to the script:

<?php
echo "\u{0124}";
echo "\u{112}";
echo "\u{13B}";
echo "\u{13B}";
echo "\u{014C}";
?>

If you run the script, a UTF-8 string ĤĒĻĻŌ will be printed out.

Grouping allowed in  ‘use’  statement for Aliasing Namespaces

Before PHP 7.0, each class, function, and constant imported from the same namespace had to be specified with a separate use statement.  With PHP 7.0, classes, functions, and constants may be grouped under the same use statement even when imported from the same namespace. Additionally, as of PHP 7, a trailing comma is allowed when grouping imports.

As an example, create a script catalog.php and declare some classes, functions, and constants belonging to the same  namespace as listed here:

<?php
namespace Catalog;
class ClassA{
function hello(){
return "Hello from classA";
}
}
class ClassB{
function hello(){
return "Hello from classB";
}
}
class ClassC{
function hello(){
return "Hello from classC";
}
}
 
function fn_a(){
return "Message from fn_a()";
}
function fn_b(){
return "Message from fn_b()";
}
function fn_c(){
return "Message from fn_c()";
}
define("Catalog\ConstA", 1);
define("Catalog\ConstB", 2);
define("Catalog\ConstC", 3);
?>

As you can see, while  constants declared using define() must specify their fully qualified name, the same does not apply to constants declared with const. Create another script group-namespace.php and import the classes, functions, and constants defined in  catalog.php. The script includes a require statement for catalog.php. The classes, functions and constants are group-imported with use:

<?php
require('catalog.php');
use Catalog\{ClassA as A, ClassB as B, ClassC as C,};
use function  Catalog\{fn_a, fn_b, fn_c,};
use const Catalog\{ConstA, ConstB, ConstC,Const1};
$a = new A();
echo $a->hello();
echo "<br/>";
$b = new B();
echo $b->hello();
echo "<br/>";
$c = new C();
echo $c->hello();
echo "<br/>";
echo fn_a();
echo "<br/>";
echo fn_b();
echo "<br/>";
echo fn_c();
echo "<br/>";
echo ConstA;
echo "<br/>";
echo ConstB;
echo "<br/>";
echo ConstC;
?>

Run the group-namespace.php script to access the group-imported classes, functions, and constants and output their value.

Hello from classA
Hello from classB
Hello from classC
Message from fn_a()
Message from fn_b()
Message from fn_c()
1
2
3

Short Array Syntax for Destructuring Arrays for Assignment

We mentioned earlier that support for unpacking a string with list() has been removed from PHP 7. Anyway, list() continues to support unpacking or destructuring  an array for assignment to variables.  In PHP 7.1, a short form array syntax has been added to unpack or destructure an array.  To demonstrate the use of the short form array syntax, create a script array_syntax.php and create a two-dimensional array for different magazines with an id assigned to each magazine:

$catalog = [
	[1, 'Oracle Magazine'],
	[2, 'Java Magazine'],
	[3, 'PHP Magazine'],
];

To use the list() to destructure or unpack the $catalog array into $id and $journal_name, you could use the following syntax:

list($id1, $journal_name_1) = $catalog[0];
list($id2, $journal_name_2) = $catalog[1];
list($id3, $journal_name_3) = $catalog[2];

Alternatively, you could use the new array destructuring syntax as follows:

[$id1, $journal_name_1] = $catalog[0];
[$id2, $journal_name_2] = $catalog[1];
[$id3, $journal_name_3] = $catalog[2];

The list() function may be used in foreach() construct as shown in the following example:

foreach ($catalog as list($id, $journal_name)) {
 	echo "Journal $id is $journal_name";
echo "<br/>";
}

The equivalent foreach using the array syntax [] is presented here:

foreach ($catalog as [$id, $journal_name]) {
	echo "Journal $id is $journal_name";
echo "<br/>";
}

The complete array_syntax.php script is listed below:

<?php
$catalog = [
	[1, 'Oracle Magazine'],
	[2, 'Java Magazine'],
	[3, 'PHP Magazine'],
];
 echo "list() syntax";
echo "<br/>";
list($id1, $journal_name_1) = $catalog[0];
list($id2, $journal_name_2) = $catalog[1];
list($id3, $journal_name_3) = $catalog[2];
echo "Journal $id1 is $journal_name_1";
echo "<br/>";
echo "Journal $id2 is $journal_name_2";
echo "<br/>";
echo "Journal $id3 is $journal_name_3";
echo "<br/>";
echo "[] syntax";
echo "<br/>";
[$id1, $journal_name_1] = $catalog[0];
[$id2, $journal_name_2] = $catalog[1];
[$id3, $journal_name_3] = $catalog[2];
echo "Journal $id1 is $journal_name_1";
echo "<br/>";
echo "Journal $id2 is $journal_name_2";
echo "<br/>";
echo "Journal $id3 is $journal_name_3";
echo "<br/>";
echo "list() syntax";
echo "<br/>";
foreach ($catalog as list($id, $journal_name)) {
 	echo "Journal $id is $journal_name";
echo "<br/>";
}
echo "[] syntax";
echo "<br/>";
foreach ($catalog as [$id, $journal_name]) {
	echo "Journal $id is $journal_name";
echo "<br/>";
}
?>

If you run the script, you will see the new short form array syntax performs the same array unpacking and outputs the same values as list(), as shown below:

list() syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
[] syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
list() syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine
[] syntax
Journal 1 is Oracle Magazine
Journal 2 is Java Magazine
Journal 3 is PHP Magazine

Related to this, the array_column function returns the value for a single column in an input array. The column is identified by $column_key in the following syntax

array array_column ( array $input , mixed $column_key [, mixed $index_key = NULL ] )

PHP 7.0.0 added support for the input parameter to be an array of objects. To demonstrate this, create a script array_column.php and declare a class Catalog with two fields $title and $edition. Create two instances of Catalog and set values for both. Then create an array of objects containing the two Catalog objects:

$catalogs = array($Catalog1, $Catalog2);

Finally, get the value of each of the two fields from the array of objects using the array_column() function:

print_r(array_column($catalogs, 'title'));
print_r(array_column($catalogs, 'edition'));

The array_column.php script is listed here:

<?php
class Catalog
{
	public $title;
	public $edition;
}
$Catalog1 = new Catalog();
$Catalog1->title = 'Oracle Magazine';
$Catalog1->edition = 'January-February2018';
 
$Catalog2 = new Catalog();
$Catalog2->title = 'Java Magazine';
$Catalog2->edition = 'March-April2018';
$catalogs = array($Catalog1, $Catalog2);
print_r(array_column($catalogs, 'title'));
print_r(array_column($catalogs, 'edition'));
?>

If you run the script, it will output the field values from the two Catalog objects:

Array ( [0] => Oracle Magazine [1] => Java Magazine ) Array ( [0] => January-February2018 [1] => March-April2018 )

Support for Class Constant Visibility

PHP  7.1 has added support for class constant visibility, which implies that constants may be declared public, protected and private. Public constants are accessible wherever the class in which they are declared is accessible. Protected constants are accessible in the same class and subclasses. Private constants are accessible only within the same class. To demonstrate the use of class constant visibility, create a script constants.php and declare a class called constants. Within the class declare four constants: one with no access modifier, a second one with public access modifier, a third with protected access modifier, and a fourth constant with private access modifier:

const A = 'A';
	public const B = 2;
	protected const C = 'C';
	private const D = 4;

The default visibility of class constants is public. Define now three  functions: fn_a() with public access modifier, fn_b() with private access modifier, and fn_c()  with protected access modifier.  Each function outputs the value of each of the four constants previously defined:

echo constants::A;
echo constants::B;
echo constants::C;
echo constants::D;

From fn_a() invoke fn_b().

$this->fn_b();

From fn_b() invoke function fn_c().

$this->fn_c();

To show that all constants declared within the class are accessible from the same class regardless of the visibility or access modifiers used, create an instance of class constants and invoke the fn_a() function, which in turn invokes fn_b(), which in turn invokes fn_c():

$constants=new constants();
$constants->fn_a();

To show that private constants are accessible within the same class they are declared in and protected constants are accessible only from a subclass and within the same class as declared, declare a class ClassA and output the value of each of the constants within a function fn_a():

class ClassA{
public function fn_a(){
echo constants::A;
echo constants::B;
echo constants::C; 
echo constants::D;
}

Finally, to show that while public and protected constants are accessible from a subclass, private constants are not, declare a subclass of class constants and output the value of each constant within a function fn_d():

class ClassB extends constants{
public function fn_d(){
echo constants::A;
echo constants::B;
echo constants::C;
echo constants::D;
}

The constants.php script is listed:

<?php
class constants
{
	const A = 'A';
	public const B = 2;
	protected const C = 'C';
	private const D = 4;
public function fn_a(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
echo constants::D;
echo "<br/>";
$this->fn_b();
}
private function fn_b(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
echo constants::D;
echo "<br/>";
$this->fn_c();
}
protected function fn_c(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
echo constants::D;
echo "<br/>";
}
}
class ClassA{
public function fn_a(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
//echo constants::C; Uncaught Error: Cannot access protected const constants::C 
echo "<br/>";
//echo constants::D;Uncaught Error: Cannot access private const constants::D
echo "<br/>";
}
}
class ClassB extends constants{
public function fn_d(){
echo constants::A;
echo "<br/>";
echo constants::B;
echo "<br/>";
echo constants::C;
echo "<br/>";
//echo constants::D;Uncaught Error: Cannot access private const constants::D
echo "<br/>";
}
 }
$constants=new constants();
$constants->fn_a();
$classA=new ClassA();
$classA->fn_a();
$classB=new ClassB();
$classB->fn_d();
?>

If you try to run the script, the echo  statement shown below  will generate the following error: Uncaught Error: Cannot access protected const constants::C.

class ClassA{
	public function fn_a(){
…
   echo constants::C; 
…
	}
..
}

Being a protected constant, constants::C cannot be accessed from any class that is not derived from catalogs. Now, comment out that statement and rerun the script. The script generates an error Uncaught Error: Cannot access private const constants::D at the following statement:

class ClassA{
 	public function fn_a(){
 …
	echo constants::D; 
…
	}
…
}

Being a private constant, constants::D it cannot be accessed from any other class. Comment out that statement and run the script again. The script generates now another error: Uncaught Error: Cannot access private const constants::D at the following statement:

class ClassB extends constants{
public function fn_d(){
 ...
echo constants::D; 
…
}
…}

Constant constants::D being a private constant, you cannot access it from a subclass. Comment out that statement and rerun the script. Now, you will get the following output:

A

2

C

4

A

2

C

4

A

2

C

4

A

2





A

2

C

Multiple Exceptions Per catch Block

Multiple exceptions may be now specified in the same catch block of a try/catch statement, using the pipe character ‘|’ as a separator. This feature is useful if multiple exceptions need to be handled in the same way. To demonstrate the use of a multi-exception catch block, create a script multi-catch-exception.php and copy the following listing to it. The script declares two custom exception classes and a try/catch statement in another class’s (MultiCatch) function test() which declares multiple exceptions in its catch block:  

try {
        	throw new CustomException_2();
    	} catch (CustomException | CustomException_2 $e) {
            var_dump(get_class($e));
    	}

The script multi-catch-exception.php is listed below:

<?php
class CustomException extends Exception { }
class CustomException_2 extends Exception { }
class MultiCatch {
	public function test() {
    	try {
        	throw new CustomException_2();
    	} catch (CustomException | CustomException_2 $e) {
            var_dump(get_class($e));
        }
	}
}
$multiCatch = new MultiCatch;
$multiCatch->test();
?>

If you run the script, the exception thrown in the try block is caught in the catch block as shown below:

string(17) "CustomException_2"

Extension Loading Syntax improved

The extension loading syntax available in php.ini has been improved.  Shared extensions do not require the .dll (on Windows) and .so (on Unix) suffixes anymore. For example, the MySQL database and Oracle database extensions may be specified as follows:

extension=mysqli
extension=oci8_12c

Keywords as Identifiers

With PHP 7.0.0, keywords may be used as property, constant, and method names for classes, interfaces, and traits. To demonstrate this, create a script reserved_restriction.php and copy the following code to it. The script declares variable names using reserved keywords (int, iterable). It also declares a constant called null (a keyword), and a function called true(a keyword).

<?php
class Catalog {
	public $int = 'hello ' . 'php';
	public $iterable = '';
	const null = 'null';
	function true() {
	}
}
$catalog=new Catalog();
 $catalog->true();
?>

If you run the script, no error message is output. An exception to the possibility to use keywords as identifiers is that a constant cannot be named class. To demonstrate this, add the following line to the preceding script:

const class=1;

If you run the script, the following error message is generated:

A class constant must not be called 'class'; it is reserved for class name fetching.

Flexible Heredoc and Nowdoc Syntax

Let’s start with a review of Heredoc and Nowdoc syntax. Heredoc is similar to double-quoted strings, with start and end markers replacing quotes.    With heredoc, after the start <<< operator you can specify an arbitrary identifier followed by a newline. A string follows, and  the same identifier closes the quotation. Nowdoc is similar to Heredoc except that the start marker is enclosed in a single quote '' and no parsing is done inside a Nowdoc.

PHP 7.3 has introduced flexible Heredoc and Nowdoc syntax for better readability with the following improvements:

  1. The closing marker does not need to be followed by a semicolon (‘;’).
  2. The closing marker does not need to be followed by a newline.
  3. The closing marker may be indented with tabs or spaces. Tabs and spaces cannot be mixed. The string text within the doc may be indented to a level the same or greater than the indentation level of the closing marker.
  4. The closing identifier is identified by a continuous, standalone marker that is the same as the starting marker.

Next, we shall demonstrate the new syntax with a few examples.   But first let’s recall the old syntax: 

print <<<EOT

Heredoc is similar to double-quoted string, with start and end markers replacing quotes.

EOT;

Heredoc could also be assigned to a variable:

<?php
class A {
	public $a = <<<EOT
An example of heredoc as a variable value.
EOT;
}
?>

The following is an example of an heredoc using the new syntax.

<?php
$str = <<<EOD
	The heredoc string	
EOD;
echo <<<EOT
    	The heredoc string	line 1
   	The heredoc string	line 2
  	The heredoc string	line 3
  	EOT
?>

The following script instead is not a valid heredoc syntax and generates the following error: Parse error: Invalid indentation - tabs and spaces cannot be mixed.

<?php
{
 	echo <<<END
	        	Heredoc text
            	END;
}
?>

An example of the Nowdoc before syntax is the following.

print <<<'EOT'

Nowdoc is similar to heredoc except that the start marker is enclosed in a single quote '' and no parsing is done inside a nowdoc.

EOT;

 An example of the new nowdoc syntax is as follows.

<?php
$str = <<<EOD
	The heredoc string	
EOD;
echo <<<'EOT'
    	The nowdoc string	line 1
   	The nowdoc string	line 2
  	The nowdoc string	line 3
  	'EOT' 
?>

Because no parsing is done inside nowdoc, the following example contains redundant code within the nowdoc string:

<?php
$str = <<<'EOD'
The heredoc  text.
EOD;
class A
{
	var $a;
	var $b;
	function __construct()
	{
        $this->a = 'A';
        $this->b = array('B1', 'B2', 'B3');
	}
}
$A = new A();
$c = 'C';
echo <<<'EOT'
  	Value of variable is "$c". Value of a variable from a class A is  "$A->a".
 	Value of an array element from class A is "{$A->b[2]}".
	Unicode  for 'B' is U+0042
   EOT
?>

Because no parsing is done the preceding script generates the following output.

Value of variable is "$c". Value of a variable from a class A is "$A->a". Value of an array element from class A is "{$A->b[2]}". Unicode for 'B' is U+0042

As mentioned, heredoc and nowdoc body indentation levels must be at least the same as those of the closing marker. To  demonstrate this, run the following script.

<?php

echo <<<'EOT'
  	Line 1
 	Line 2
	Line 3
 	EOT
?>

In this case,  the following error is generated:

Invalid body indentation level (expecting an indentation level of at least 5

Support for Reference Assignments in Array Destructuring

PHP 7.3 added support for reference assignments in array and list() destructuring. First let’s review what assignments in array/list destructuring are. In the following script, an array is destructured and its element values assigned to a list:

<?php
list($a[], $a[], $a[]) = ['A', 2, 3];
var_dump($a);
?>

The var_dump statement  generates the following output:

array(3) { [0]=> string(1) "A" [1]=> int(2) [2]=> int(3) }

Now, let’s consider an example of the new syntax:

list(&$a, [$b, &$c]) = $d

In this case, the list elements $a and $c are assigned by reference.  As an example, create the following script where  the $array[1] element is assigned by reference to the $bvariable. This means that if $b   is assigned a new value, the new value is also assigned to $array[1].

<?php
$array = ['A', 2];
list($a, &$b) = $array;
echo $a;
echo "<br/>";
echo $b;
echo "<br/>";
echo $array[1];
$b='b';
echo "<br/>";
echo $array[1];

The output from the script is as follows:

A
2
2
b

If the same script is run without assignment by reference, the output would be different.

list($a, $b) = $array;

The output with the preceding assignment is as follows:

A
2
2
2

Finally, let’s consider an example of reference assignment in array destructuring. In the following script an array element is assigned a value by reference to a variable $b. If the value of $b is changed, so is the value of the array element.

<?php
$array = [1, &$b];
 
$b='B';
echo $array[0];
echo "<br/>";
echo $array[1];
$b=2;
echo "<br/>";
echo $array[1];

Run the script and you will get the following output:

1
B
2

Instanceof Accepts literals

Let’s start with a review of the instanceof operator. In the following script, instanceof is used to find out if an object is an instance of class A:

<?php
class A{}
$obj = new A();
echo ($obj instanceof A);
?>

If you run the script, an output of 1 is generated.

PHP 7.3 has added support for using literals as the first operand. In the following script the first operand to instanceof is a string literal:

<?php
class A{}
echo ('Hello PHP' instanceof A); 
?>

If you run the script, FALSE is output. If the first operand is a literal, instanceof output is always FALSE.

Null Coalescing Assignment

We discussed earlier the null coalescing operator ?? introduced in PHP 7.0. PHP 7.4 takes the null coalescing operator ?? further by adding support for null coalescing assignments. As an example, consider the following case. you use isset() to determine if an array key is set and, if it is not, you set a value for it 

if (!isset($a['4'])) {
    $a['4'] = setDefault();
}

The following script demonstrates using null coalescing assignment for the same conditional setting of an array key:

<?php
$a = array('1' => 'one', '2' => 'two', '3' => 'three');
$a['4'] ??= setDefault();
function setDefault()
{ 
    return 'four';
}
var_dump($a);//array(4) { [1]=> string(3) "one" [2]=> string(3) "two" [3]=> string(5) "three" [4]=> string(4) "four" }

?>

Numeric Literal Separator

Numeric literals with many digits may become undecipherable due to their length, which could make debugging rather  difficult. PHP 7.4 introduces underscore as a numeric literal separator to improve readability of code. The following script makes use of the _ digit separator in variables of different types.

$_1=10_;       // trailing

$_2=1__2;       // next to underscore

$_3=5_.0; 1._0; // next to decimal point

$_4=0x_123;     // next to x

$_5=0b_111;     // next to b

The only requirement to use underscore as a numeric literal separator is that it must appear between two digits. Specifically, it cannot be trailing a digit, nor  appear next to another underscore or next to a decimal point. A variable name may still start with an underscore. The following are all examples of _ used  as a numeric literal separator in incorrect ways: 

$_1=10_;       // trailing
$_2=1__2;       // next to underscore
$_3=5_.0; 1._0; // next to decimal point
$_4=0x_123;     // next to x
$_5=0b_111;     // next to b
$_6=2_e3; 2e_3; // next to e

 The underscores in numeric literals are removed during lexing.

Spread Operator for unpacking inside an Array 

The spread operator denoted by three consecutive dots … was already supported for argument unpacking in a function signature.  PHP 7.4 adds support for the spread operator to unpack elements of an array. The main characteristics of spread operator support in arrays are the following:

  • Arrays and objects that implement Traversable may be used with the spread operator.
  • The spread operator may be used anywhere in an array, before or after its elements and even consecutively. 
  •  It may be used with both  array syntax (array()) and short syntax ([]). 
  • An array returned by a function may be unpacked with the score operator.
  • An array cannot be unpacked by reference. If elements of an array to be unpacked are stored by reference, they continue to be stored by reference after unpacking.
  • String keys are not supported.

The following script demonstrates the use of the spread operator. Array element ...$cd makes use of the spread operator. Array element ,...getArr() unpacks an array returned by a function. 

<?php
$cd = ['c', 'd'];
$af = ['a', 'b', ...$cd,'e','f'];
var_dump($af);  

function getArr() {
  return ['c', 'd'];
}
$af = ['a', 'b',...getArr(), 'e','f'];  

var_dump($af); 
?>

Each var_dump statement outputs:

array(6) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" [3]=> string(1) "d" [4]=> string(1) "e" [5]=> string(1) "f" }

To verify that string keys cannot be used with the spread operator, run the following script:

<?php
$cd = array("c" => "c","d" => "d");
$af = ['a', 'b', ...$cd,'e','f'];
var_dump($af);

 

The following  error message is displayed:

Uncaught Error: Cannot unpack array with string keys

Deprecated Curly Brackets Syntax for Accessing Array Elements

PHP 7.4 deprecates the use of curly brackets to access array elements and string offsets. The curly brackets syntax has only limited functionality anyway; for example it cannot be used to create an array or to push an element into an array,  and  cannot be used for list assignment. The following script can still be used and generates the expected output string (1) "a". 

<?php

$arr = ['a', 'b', 'c'];

var_dump($arr{0});

However, it also displays a warning message:

Deprecated: Array and string offset access syntax with curly braces is deprecated

Summary

In a series of five articles we have explored the salient new features in PHP 7.x grouped by feature categories. In the first article PHP 7 — Getting Started and OOP Improvements we set the environment for running PHP 7.x scripts and introduced object oriented programming related improvements. In the second article  PHP 7 — Classes and Interfaces Improvements we introduced improvements to classes and interfaces. In the third article PHP 7 — New Features for Types we introduced improvements in PHP's type system. In the fourth article PHP 7 – Functions Improvements we introduced functions related improvements. In this final article in the series we conclude with improvements not covered by earlier articles and these include improvements to arrays, operators, constants, and exception handling.

PHP 8.0 is expected to made available in early December 2020 with a new set of features, but till then brush up on your PHP 7.x. 

About the Author

Deepak Vohra is a Sun Certified Java Programmer and Sun Certified Web Component Developer. Deepak has published Java and Java EE related technical articles in  WebLogic Developer's Journal, XML Journal, ONJava, java.net, IBM developerWorks, Java Developer’s Journal, Oracle Magazine, and devx. Deepak has published five books on Docker and is a Docker Mentor. Deepak has also published several articles on PHP and a book Ruby on Rails for PHP and Java Developers.

 

PHP 7.x brings several improvements and new features that touch all aspects of the language, including better support for object oriented programming, extensions to classes and interfaces, improvements to the type system, error handling, and more. In this series of articles, we discuss new features across the various PHP 7.x versions.

 

Rate this Article

Adoption
Style

BT