CentrioHost Blog

Stories and News from IT Industry, Reviews & Tips | Technology Blog


What’s New in PHP 7.3 (Now Available at Host SEO)

  • Category : Development
  • Posted on : Nov 20, 2018
  • Views : 3,068
  • By : Radcliff S.

What’s New in PHP with PHP 7.3?

In this post we’re covering the following PHP 7.3 changes:

  • Implemented Flexible Heredoc And Nowdoc Syntaxes
  • Allow a Trailing Comma in Function Calls
  • JSON_THROW_ON_ERROR
  • list() Reference Assignment
  • is_countable Function
  • array_key_first(), array_key_last()
  • Argon2 Password Hash Enhancements
  • Deprecations

Flexible Heredoc and Nowdoc Syntaxes

This is probably one of the most relevant improvements coming with PHP 7.3, and we think it deserves a little more attention. So, before diving into PHP 7.3 heredoc/nowdoc changes, we’ll provide a quick overview of this useful core feature. If you are already confident with nowdoc and heredoc, feel free to jump to the PHP 7.3 changes.

  • An overview of heredoc and nowdoc syntaxes
  • PHP 7.3: Allow for the closing marker to be indented and for the leading whitespace to be stripped
  • PHP 7.3: Remove the Trailing New Line Requirement From the Closing Marker

An overview of heredoc and nowdoc syntaxes

The heredoc syntax provides a way of adding a large amount of text without the need to escape things like double quotes. A heredoc starts with <<< followed by a marker, and ends with the same marker followed by a semicolon. Here is an example:

print <<<EOT
Heredoc text behaves just like a double-quoted string, without the double quotes.
EOT;

A nowdoc behaves much like a heredoc, with some exceptions:

  • The identifier is enclosed in single quotes (<<<'EOT')
  • No parsing is done inside a nowdoc

Here is an example of nowdoc:

print <<<'EOT'
Nowdocs are to single-quoted strings what heredocs are to double-quoted strings.
EOT;

Heredocs and nowdocs share the same rules regulating the usage of the closing marker:

  1. The closing marker must begin in the first column of the line
  2. The marker must follow the same naming rules as any other label in PHP: it must contain only alphanumeric characters and underscores, and must start with a non-digit character or underscore.

The PHP Manual warns:

It is very important to note that the line with the closing identifier must contain no other characters, except a semicolon (;). That means especially that the identifier may not be indented, and there may not be any spaces or tabs before or after the semicolon. It’s also important to realize that the first character before the closing identifier must be a newline as defined by the local operating system. This is n on UNIX systems, including macOS. The closing delimiter must also be followed by a newline.

PHP 7.2 invalid syntax:

class foo {
    public $bar = <<<EOT
    bar
    EOT;
}
// Identifier must not be indented

PHP 7.2 valid syntax:

class foo {
    public $bar = <<<EOT
bar
EOT;
}

To keep it short, in PHP 7.2:

  • The closing marker may not be indented
  • The line with the closing marker may not contain characters like spaces or tabs
  • The first character before the closing marker must be a newline
  • The closing marker must be followed by a newline

It’s clear enough that heredoc and nowdoc syntaxes are quite restrictive, but PHP 7.3 may change this a little with the following improvements.

1. Allow for the closing marker to be indented and for the leading whitespace to be stripped

With PHP 7.3 we are allowed to indent the closing marker, and we can safely write the following code:

class foo {
    public $bar = <<<EOT
        bar
    EOT;
}

The indentation of the closing marker sets the amount of whitespace (or tabs) that will be stripped from each line of the body. But be careful: the closing marker should never be indented further than any other line of the body.

See the code below:

class foo {
    public $bar = <<<EOT
    bar
        EOT;
}

The code above would issue the following parse error:

Parse error: Invalid body indentation level (expecting an indentation at least ...) in %s on line %d

Stripping tabs and whitespaces allow us to indent the body of the heredoc/nowdoc to the same level of the code around, and without unnecessary whitespace before each line of the body.

We can use both tabs and spaces for indentation, but we are not allowed to use them intermixed. This means that we must use the same indentation characters for the closing marker and any lines of the body. In case of different indentation characters, we’d expect a different type of parse error (invalid indentation).

2. Remove the Trailing New Line Requirement From the Closing Marker

Currently, a new line must follow the marker in order to terminate the heredoc/nowdoc. PHP 7.3 would change this and would allow us to terminate the heredoc/nowdoc on the same line. Here is an example from the RFC:

PHP 7.2 valid syntax:

$values = [<<<END
a
b
c
END
, 'd e f'];

PHP 7.3 valid syntax:

$values = [<<<END
a
b
c
END, 'd e f'];

Anyway, be careful when choosing the name of your marker because “occasionally” you may expect an error if it matches a word you used in the body of the heredoc/nowdoc (read more on this on the RFC and GitHub).

Both proposals passed with more than 2/3 votes.

PHP 7.3 RFC

  • Flexible Heredoc and Nowdoc Syntaxes

Additional Resources

  • Heredoc string syntax
  • Nowdoc string syntax

Allow a trailing comma in function calls

Trailing commas (or “final commas”) are commas appended to a list of elements, parameters or properties and they come in handy in contexts where new values are appended frequently because they prevent errors due to a missing comma. In PHP trailing commas are allowed in arrays, and as of PHP 7.2 they are allowed in grouped namespaces.

As of PHP 7.3, trailing commas would be allowed in function declarations. Variadic functions provide an example of context where trailing commas are extremely useful:

foo(
    $bar,
    $baz,
);

We can use a trailing comma when we are creating an array with compact(), in order to return a formatted string with sprintf(), or when merging an array:

$newArray = array_merge(
    $arrayOne,
    $arrayTwo,
    ['foo', 'bar'],
);

Also, trailing commas would be useful for debugging:

var_dump(
    $foo,
    $bar,
    $baz,
);

And they are powerful with unset() and isset():

unset(
    $foo,
    $bar,
    $baz,
);
isset(
    $foo,
    $bar,
    $baz,
);

Trailing commas will be allowed in method calls and enclosures, as well.

Note: This change would affect function calls only. Function declaration syntax will not change. Moreover, free-standing commas, multiple trailing commas, and leading commas will not be allowed.

Additional examples can be found on the RFC page. This RFC passed with a 30 to 10 vote.

PHP 7.3 RFC

  • Flexible Heredoc and Nowdoc Syntaxes

JSON_THROW_ON_ERROR

One of the most appreciated functionalities coming with PHP 7.3 provides a new way of handling JSON errors. This is not a core feature, but an addition to the JSON extension that would change the error behaviour of json_decode() and json_encode().

Currently, json_decode() returns null on error, but null can also be a valid result. This could be confusing, because

It is only possible to know if an error occurred by calling json_last_error() or json_last_error_msg(), which return the global error state in machine-readable and human-readable forms respectively. – PHP RFC

json_encode() returns FALSE on error. This is clearer because there is a specific error value. Anyway, both functions neither halt program execution on error, nor throw any warning.

With that being said, here is the proposal for PHP 7.3:

This RFC instead proposes adding a new option flag value for json_decode() and json_encode()JSON_THROW_ON_ERROR. When passed this flag, the error behaviour of these functions is changed. The global error state is left untouched, and if an error occurs that would otherwise set it, these functions instead throw a JsonException with the message and code set to whatever json_last_error() and json_last_error_msg() would otherwise be respectively.

Here is an example showing a simple way of throwing a JSON error:

try {
    json_decode("{", false, 512, JSON_THROW_ON_ERROR);
}
catch (JsonException $exception) {
    echo $exception->getMessage(); // echoes "Syntax error"
}

Throwing an exception upon error would give several advantages that you’ll find listed on the RFC.

Note: an invalid depth parameter passed to json_decode() outputs a warning and returns NULL. This behaviour will not be affected by JSON_THROW_ON_ERROR. Similarly, parameter parsing errors are not affected by JSON_THROW_ON_ERROR and continue to produce warnings.

This proposal passed with 23 to 0 votes.

PHP 7.3 RFC

  • JSON_THROW_ON_ERROR

Additional Resources

  • JavaScript Object Notation
  • json_decode()
  • json_encode()
  • json_last_error()
  • json_last_error_msg()
  • PHP Language Exceptions

list() Reference Assignment

What Does Reference Assignment Mean?

Consider the following line:

$b = &$a;

Here $b gets the value of $a, but that value is not copied from $a to $b. In PHP we can assign a value by reference, meaning that two variables may point to the same data, and every change to any variable affects the original data. Here is an example from the PHP manual:

<?php
$a = 3;
$b = &$a; // $b is a reference to $a
print "$an"; // prints 3
print "$bn"; // prints 3

Now, let’s change the value of $a:

$a = 4; // change $a
print "$an"; // prints 4
print "$bn"; // prints 4 as well, since $b is a reference to $a, which has been changed

What Is The list() Construct and How It Changes With PHP 7.3

The list() language construct can be used to “assign variables as if they were in an array”, but with list() we are not currently allowed to assign variable values by reference.

PHP 7.3 should change this allowing us to assign variables by reference also with the list() construct, as shown in the following example:

$array = [1, 2];
list($a, &$b) = $array;

Which is the same as:

$array = [1, 2];
$a = $array[0];
$b =& $array[1];

The advantage of this proposal is that we could now assign multiple variables by reference, which was not currently allowed. More examples are available on the RFC. This proposal passed with 17 to 7 votes.

PHP 7.3 RFC

  • list() Reference Assignment

Additional Resources

  • PHP Manual – list()
  • PHP Manual – References Explained
  • Assignment Operators – Assignment by Reference

is_countable Function

Another useful feature coming with PHP 7.3 is the is_countable() function. Up to PHP 7.2, we get an error when attempting to count() something that is not countable. For this reason, in order to avoid a warning, we are forced to add the following code:

if (is_array($foo) || $foo instanceof Countable) {
    // $foo is countable
}

This RFC proposes the function is_countable(), which returns true if the given variable is an array or it is a countable variable, false otherwise. So, the code above could be changed as