Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Mastering PHP 7
Mastering PHP 7

Mastering PHP 7: Design, configure, build, and test professional web applications

eBook
€8.99 €29.99
Paperback
€36.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Mastering PHP 7

The All New PHP

Programming languages nowadays are a dime a dozen. New languages spring into existence every so often. Choosing the right one for the job is so much more than just a checklist of its features. Some of them target specific problem domains, others try to position themselves for more general use. This goes to say that software development is a dynamic ecosystem where languages need to constantly adapt to ever-changing industry in order to stay relevant to its consumers. These changes are particularly challenging for already established languages such as PHP, where backward compatibility is an important consideration.

Originally created by Rasmus Lerdorf around 1995, PHP started its life as nothing more than a few Common Gateway Interface (CGI) programs in C. At that time, it was a simple scripting solution that empowered developers to build dynamic HTML pages with ease. Without the need to compile, developers could easily throw in a few lines of code into a file and see the results in the browser. This gave a rise to its early popularity. Two decades later, PHP matured into a rich general-purpose scripting language suited to web development. Throughout all these years, PHP managed to yield an impressive set of features with each new release whilst maintaining a trustworthy level of backward compatibility. Nowadays, large number of its core extensions ultimately simplify working with files, sessions, cookies, databases, web services, cryptography, and many other features common to web development. Its outstanding support for the object-oriented programming (OOP) paradigm made it truly competitive with other leading industry languages.

The decade-old ruling of PHP 5 has been overthrown by the release of PHP 7 in December 2015. It brought forth the all new execution engine, Zend Engine 3.0, which significantly improved performance and reduced memory consumption. This simple software update now allowed us to serve more concurrent users without adding any physical hardware to the mix. Acceptance among developers has been almost instant, all the more so because backward incompatibility was minimal, making migration as painless as possible.

In this chapter, we will take a detailed look into some of the new features introduced in PHP 7 and 7.1 releases:

  • Scalar type hints
  • Return type hints
  • Anonymous classes
  • Generator delegation
  • Generator return expressions
  • The null coalesce operator
  • The spaceship operator
  • Constant arrays
  • Uniform variable syntax
  • Throwables
  • Group use declarations
  • Class constant visibility modifiers
  • Catching multiple exceptions types
  • Iterable pseudo-type
  • Nullable types
  • Void return types

It is features like these that are bound to make a mark on the next generation of PHP frameworks and libraries, as well as how we write our own code.

Scalar type hints

By classification, PHP is a dynamically typed and weakly typed language. These are two different concepts that often get mixed together. Dynamically typed languages do not require the explicit declaration of a variable before it is used. Weakly typed languages are those in which the variable is not of any specific data type, that is, its type can change through different value-type reassignments.

Let's take a look at the following example:

// dynamic typed (no specific type defined, directly assigning value)
$name = "Branko"; // string
$salary = 4200.00; // float
$age = 33; // int

// weak typed (variable value reassigned into different type)
$salary = 4200.00; // float
$salary = $salary + "USD"; // float
$salary = $salary . "USD"; // string

In the preceding code, we see three different variables being used, none of which are predefined with a certain type. We just have values declared into them. PHP then determines the type on the go. Even when the variable type is determined, it can still be changed by simply assigning another type of value to it. These are two very powerful concepts, which, when used wisely, can save us lines and lines of code.

However, these powerful features often indirectly encourage bad design. This is particularly noticeable when writing functions, either by forcing function designers into multiple data type checks, or forcing them into multiple function return types.

Let's take a look at the following example:

function addTab($tab) {
if (is_array($tab)) {

} elseif (is_object($tab)) {

} elseif (is_string($tab)) {

} else {

}
}

Given the type uncertainty of the input argument, the addTab function was forced to branch its logic. Similarly, the same function might decide to return different types of data, depending on the logic branch. Designs like these are usually a result of functions that simply try to do too much. The real problem is not even in the function, it is on the consumer side of things. If it happens that the developer using a function is not aware enough of the passing parameter type, unexpected results might occur.

To help us write more correct and self-documenting programs, PHP introduced type hinting.

PHP has supported function parameter type hinting from version 5.0, but only for objects, and from version 5.1 for arrays as well. With PHP 7, scalar types can be type-hinted as well, making it one of the more exciting features of the release. The following are the scalar type hints that are supported by PHP:

  • int
  • float
  • string
  • bool

We can now write functions in either of the following ways:

  • It can  be function register($email, $age, $notify) { /* ... */}
  • It can be function register($email, int $age, $notify) { /* ... */}
  • It can be function register(string $email, int $age, bool $notify) { /* ... */}

However, simply hinting scalar types is not enough as type declarations are not enforced by default. PHP will simply attempt to convert to the specified type without complaint. By adding the declare(strict_types=1); directive as the first statement in a PHP file, we can enforce the strict type checking behavior. It is worth noting that this directive only affects the specific file it is used in, and does not affect other included files. The file-level directive was used to preserve the backward compatibility with numerous extensions and built-in PHP functions.

Let's take a look at the following example:

declare(strict_types=1);

function register(string $email, int $age, bool $notify) {
// body
}

register('user@mail.com', '33', true);

With strict types directive turned on, trying to pass an improper data type to a hinted scalar parameter would result in a \TypeError exception, as per the following output:

Fatal error: Uncaught TypeError: Argument 2 passed to register() must be of the type integer, string given, called in /test.php on line 11 and defined in /test.php:5 Stack trace: #0 /test.php(11): register('user@mail.co...', '33', true) #1 {main} thrown in /test.php on line 5.

Scalar type hints are a powerful new addition to the PHP language. They empower developers with an extra layer of protection during runtime, without really sacrificing the weak type system in general.

Return type hints

Type hinting features are not limited to function parameters only; as of PHP 7, they expand to function return values as well. The same rules that apply to function parameters hinting, apply to function return type hinting. To specify a function return type, we simply follow the parameter list with a colon and the return type, as shown in the following example:

function register(string $user, int $age) : bool {
// logic ...
return true;
}

Developers can still write functions with multiple conditioned return statements; its just that in this case, each of these return statements, when reached, will have to match the hinted return type, otherwise \TypeError will be thrown.

The function return type hints play nicely with super types. Let's take a look at the following example:

class A {}
class B extends A {}
class C extends B {}

function getInstance(string $type) : A {
if ($type == 'A') {
return new A();
} elseif ($type == 'B') {
return new B();
} else {
return new C();
}
}

getInstance('A'); #object(A)#1 (0) { }
getInstance('B'); #object(B)#1 (0) { }
getInstance('XYZ'); #object(C)#1 (0) { }

We see that the function executes nicely for all three types. Given that B extends A directly, and C extends B, the function accepts them as the return value.

Given the dynamic nature of PHP, function return types might seem like a step in the wrong direction at first, more so because a lot of PHP code out there already uses the PHPDoc @return annotation, which plays nicely with modern IDE tools, such as PhpStorm. However, the @return annotation is merely informative, it does not enforce an actual return type during runtime, and it really makes sense only with a powerful IDE. Using the function return type hints ensures that our functions return what we intended them to return. They do not stand in the way of PHP's dynamic nature; they merely enrich it from a function consumer point of use.

Anonymous classes

Instantiating objects from classes is a pretty straightforward action. We use the new keyword, followed by a class name and possible constructor parameters. The class name part implies the existence of a previously defined class. Though rare, there are cases where classes are only used during execution. These rare cases make it verbose to force a class definition separately when we know that the class is only being used once. To address this verbosity challenge, PHP introduced a new functionality called anonymous classes. While the concept of anonymous classes has been around for quite some time in other languages, PHP only got to it in the PHP 7 release.

The syntax of anonymous classes is pretty straightforward, which is as follows:

$obj = new class() {};
$obj2 = new class($a, $b) {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
};

We use the new keyword , followed by the class keyword, followed by optional constructor parameters, and finally the body of the class packed in curly braces. Both objects are instantiated as a class@anonymous type. The functionality of objects instantiated through anonymous classes is no different from those instantiated via named classes.

Compared to named classes, anonymous classes are pretty much equal, in that, they can pass contractor parameters, extend other classes, implement interfaces, and use traits. However, anonymous classes cannot be serialized. Trying to serialize an instance of an anonymous class, as shown in the following code snippet, throws a fatal Serialization of class@anonymous is not allowed… error.

There are few other caveats to keep in mind when using anonymous classes. Nesting an anonymous class within another class hides the private and protected methods or properties of that outer class. To circumvent the limitation, we can pass the outer class' private and protected properties into an anonymous class constructor, as follows:

interface Salary {
public function pay();
}

trait Util {
public function format(float $number) {
return number_format($number, 2);
}
}

class User {
private $IBAN;
protected $salary;
public function __construct($IBAN, $salary) {
$this->IBAN = $IBAN;
$this->salary = $salary;
}

function salary() {
return new class($this->IBAN, $this->salary) implements Salary {
use Util;
private $_IBAN;
protected $_salary;

public function __construct($IBAN, $salary) {
$this->_IBAN = $IBAN;
$this->_salary = $salary;
}

public function pay() {
echo $this->_IBAN . ' ' . $this->format($this->_salary);
}
};
}
}
$user = new User('GB29NWBK60161331926819', 4500.00);
$user->salary()->pay();

In this strip down User class example, we have a salary method that returns an anonymous class. To showcase the more robust use of anonymous classes, we make it implement the Salary interface and use the Util trait. The Salary interface forces the anonymous class to implement the pay method. Our implementation of pay method requires IBAN and salary member values from the outer class. Since an anonymous class does not allow access to private and protected members of the outer class, we pass those through anonymous class constructors. While the overall example certainly does not reflect notions of a good class design, it does showcase how to bypass the member visibility limitation.

There is also an option for an anonymous class to fetch the private and protected members of the outer class by extending the outer class itself. However, this requires the anonymous class constructor to properly instantiate the outer class; otherwise, we might end up with a warning, such as a missing argument, for User::__construct().

Even though they are namelessly defined, anonymous classes still get an internal name. Using the core PHP get_class method on an instance of an anonymous class, gets us that name, as shown in the following examples:

class User {}
class Salary {}

function gen() {
return new class() {};
}

$obj = new class() {};
$obj2 = new class() {};
$obj3 = new class() extends User {};
$obj4 = new class() extends Salary {};
$obj5 = gen();
$obj6 = gen();

echo get_class($obj); // class@anonymous/var/www/index.php0x27fe03a
echo get_class($obj2); // class@anonymous/var/www/index.php0x27fe052
echo get_class($obj3); // class@anonymous/var/www/index.php0x27fe077
echo get_class($obj4); // class@anonymous/var/www/index.php0x27fe09e
echo get_class($obj5); // class@anonymous/var/www/index.php0x27fe04f
echo get_class($obj6); // class@anonymous/var/www/index.php0x27fe04f

for ($i=0; $i<=5; $i++) {
echo get_class(new class() {}); // 5 x
class@anonymous/var/www/index.php0x27fe2d3
}

Observing these outputs, we see that the anonymous classes created in the same position (function or a loop) will yield the same internal name. Those with the same name return true for the equal (==) operator and false for the identity operator (===), an important consideration in order to avoid potential bugs.

Support for an anonymous classes opens a door to some interesting use cases, such as mocking tests and doing the inline class overrides, both of which, when used wisely, can improve code quality and readability.

Generator delegation

Iterating through a list of items is among the most common things in any programming language. PHP makes it easy to iterate over a diverse collection of data using the foreach construct. Many languages differentiate various data types of collection data, such as dictionary, list, set, tuple, and alike. PHP, however, does not dwell that much on data structures and simply uses the array() or [] constructs most of the time for its collections. This, in turn, can have a negative impact on creating large arrays in memory, which could cause exceeding memory limits or even increased processing times.

Aside from the primitive array type, PHP also provides the ArrayObject and ArrayIterator classes. These turn arrays into a first class citizens in an OOP application.

Generators allow us to write code that uses foreach to iterate over a set of data without needing to build an array. They are like a function that yields as many values as needed, instead of returning just one, which gives them an iterator-like behavior. While generators have been around from PHP 5.5, they lacked more advanced functionality. Generator delegation is one of the improvements made available with the release of PHP 7.

Let's take a look at the following example:

function even() {
for ($i = 1; $i <= 10; $i++) {
if ($i % 2 == 0) {
yield $i;
}
}
}

function odd() {
for ($i = 1; $i <= 10; $i++) {
if ($i % 2 != 0) {
yield $i;
}
}
}

function mix() {
yield -1;
yield from odd();
yield 17;
yield from even();
yield 33;
}

// 2 4 6 8 1 0
foreach (even() as $even) {
echo $even;
}

// 1 3 5 7 9
foreach (odd() as $odd) {
echo $odd;
}

// -1 1 3 5 7 9 17 2 4 6 8 10 33
foreach (mix() as $mix) {
echo $mix;
}

Here, we define three generator functions: even, odd, and mix. The mix function demonstrates the concept of generator delegation via the use of yield from <expr>. Whereas, <expr> is any expression that evaluates to a traversable object or array. We can see that the result of looping through the mix function echoes all of the yielded values from both itself as well as the even and odd functions.

The generator delegation syntax allows the factoring of yield statements into smaller conceptual units, giving generators the similar organizational functionality as methods give to classes. Used carefully, this can improve our code quality and readability.

Generator return expressions

Though PHP 5.5 enriched the language by introducing generator functions functionality, it lacked the return expressions alongside their yielded values. This inability of generator functions to specify return values limited their usefulness with coroutines. The PHP 7 version addressed this limitation by adding support for the return expressions. Generators are basically interruptible functions, where the yield statement flags the interruption point. Let's take a look at the following simple generator, written in the form of a self-invoking anonymous function:

$letters = (function () {
yield 'A';
yield 'B';
return 'C';
})();

// Outputs: A B
foreach ($letters as $letter) {
echo $letter;
}

// Outputs: C
echo $letters->getReturn();

Though the $letters variable is defined as a self-invoking anonymous function, the yield statements are preventing immediate function execution, turning the function into the generator. Generator itself stands still until we try to iterate over it. Once the iteration kicks in, generator yields value A followed by value B, but not C. What this means is that when used in the foreach construct, the iteration will only encompass yielded values, not the returned ones. Once the iteration is done, we are free to call the getReturn() method to retrieve the actual return value. Calling the getReturn() method prior to iterating over generator results cannot get the return value of a generator that hasn't returned an exception.

The great thing about the generators is that they are not a one-way street; they are not limited to only yielding values, they can accept them as well. By being the instances of a \Generator class, they operate with several useful methods, two of which are getReturn and send. The send method enables us to send values back to the generator, which turns the one-way communication from the generator to the caller into a two-way channel between the two, effectively, turning generators into coroutines. The addition of the getReturn method empowered generators with the return statements, giving more flexibility with coroutines.

The null coalesce operator

Working with variables in PHP is quite easy. Variable declaration and initialization is done via a single expression. For example, the expression $user['name'] = 'John'; will automatically declare variable $user of type array and initialize that array with a single key name of value John.

Day-to-day development often includes checking for the existence of a variable value for various branching decisions, such as if ($user['name'] =='John') { … } else { … }. As we write our code ourselves, we tend to make sure that our code does not use non-declared variables and non-initialized array keys. There are cases, however, where variables come from outside, so we are not really in a position to guarantee their existence at runtime. Calling for $user['name'] when $user is not set, or is set but with keys other than name, will result in notice undefined index--name. Like any unexpected state in code, notices are bad, more so because they do not actually break your code, they allow it to execute further. When a notice occurs, unless we have the display_errors configuration set to true, and error reporting configured to show E_ALL, we would not even see the notice in the browser.

This is bad, as we might depend on the existence of variables and their values that are not there. This dependency might not even be handled in our code, and we would not even notice it because the code will continue to execute unless a specific variable check is put in place.

The PHP language has a certain number of predefined variables called superglobals, which we can use from any function, class, or file, regardless of the scope. The most used ones are probably $_POST and $_GET superglobals, which are used to fetch the data submitted via forms or URL parameters. Since we cannot guarantee the existence of $_GET['name'] in such cases, we need to check for it. Usually, this is done using the isset and empty functions in PHP, as shown in the following code block:

// #1
if (isset($_GET['name']) && !empty($_GET['name']))
{
$name = $_GET['name'];
}
else {
$name = 'N/A';
}

// #2
if (!empty($_GET['name']))
{
$name = $_GET['name'];
}
else {
$name = 'N/A';
}

// #3

$name = ((isset($_GET['name']) && !empty($_GET['name']))) ? $_GET['name'] : 'N/A';

// #4
$name = (!empty($_GET['name'])) ? $_GET['name'] : 'N/A';

The first example is the most robust one, as it uses both, the isset and empty functions. These functions are not the same, so it's important to understand what each of them does. The good thing about an empty function is that it will not trigger a notice if we try to pass it a variable that might not be set, such as $_GET['name']; it will simply return true or false. This makes the empty function a nice helper for most cases. However, even the fourth example, written via the use of the ternary operator, is somewhat robust.

PHP 7 introduced a new type of operator called the null coalesce (??) operator. It empowers us with the ability of writing shorter expressions. The following example demonstrates the elegance of its use:

$name = $_GET['name'] ?? 'N/A';

It returns the result of its first operand if it exists and is not null, or else its second operand. In other words, reading it from left to right, the first existing value, which is not null, is the value that will be returned.

The spaceship operator

Comparing two values is a frequent operation in any programming language. We use various language operators to express the type of comparison we wish to execute between two variables. In PHP, these operators include equal ($a == $b), identical ($a === $b), not equal ($a != $b or $a <> $b), not identical ($a !== $b), less than ($a < $b), greater than ($a > $b), less than or equal to ($a <= $b), and greater than or equal to ($a >= $b) comparisons.

All of these comparison operators result in Boolean true or false. Sometimes, however, there are cases where a three-way comparison is needed, in which case, the result of the comparison is more than just a Boolean true or false. While we can achieve a three-way comparison using various operators through various expressions, the solution is all but elegant.

With the release of PHP 7, a new spaceship <=> operator has been introduced, with a syntax as follows:

(expr) <=> (expr)

The spaceship <=> operator offers combined comparison. After comparison, it follows these conditions:

  • It returns 0 if both operands are equal
  • It returns 1 if the left operand is greater
  • It returns -1 if the right operand is greater

Comparison rules used to yield the preceding results are the same as those used by existing comparison operators: <, <=, ==, >=, and >.

The usefulness of the new operator is especially apparent with ordering functions. Without it, the ordering functions were quite robust, as per the following example:

$users = ['branko', 'ivana', 'luka', 'ivano'];

usort($users, function ($a, $b) {
return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
});

We can shorten the preceding example by applying the new operator to it, as follows:

$users = ['branko', 'ivana', 'luka', 'ivano'];

usort($users, function ($a, $b) {
return $a <=> $b;
});

Applying the spaceship <=> operator, where applicable, gives the expressions simplicity and elegance.

Constant arrays

There are two types of constants in PHP, the constants and the class constants. The constants can be defined pretty much anywhere using the define construct, while the class constants are defined within the individual class or interface using the const keyword.

While we cannot say that one type of constant is more important than the other, PHP 5.6 made the difference between the two by allowing class constants with the array data type. Aside from that difference, both types of constants supported scalar values (integer, float, string, Boolean, or null).

The PHP 7 release addressed this inequality by adding the array data type to constants as well, making the following into valid expressions:

// The class constant - using 'const' keyword
class Rift {
const APP = [
'name' => 'Rift',
'edition' => 'Community',
'version' => '2.1.2',
'licence' => 'OSL'
];
}

// The class constant - using 'const' keyword
interface IRift {
const APP = [
'name' => 'Rift',
'edition' => 'Community',
'version' => '2.1.2',
'licence' => 'OSL'
];
}

// The constant - using 'define' construct
define('APP', [
'name' => 'Rift',
'edition' => 'Community',
'version' => '2.1.2',
'licence' => 'OSL'
]);

echo Rift::APP['version'];
echo IRift::APP['version'];
echo APP['version'];

Though having constants with the array data type might not be an exciting type of feature, it adds a certain flavor to the overall constant use.

Uniform variable syntax

The new variable syntax is probably one of the most impacting features of the PHP 7 release. It brings greater order into variable dereferencing. The impacting part, however, not only affects changes for better as it also introduces certain backwards compatibility (BC) breaks. Among the main reasons for these changes were inconsistencies with variable variable syntax.

Observing the $foo['bar']->baz expression, first a variable named $foo is fetched, then the bar offset is taken from the result, and, finally, the baz property is accessed. This is how normally variable accesses is interpreted, from left to right. However, the variable variable syntax goes against this principle. Observing the $$foo['baz'] variable, $foo is fetched first, then its baz offset, and finally looking for the variable with the name of the result is done.

The newly introduced uniform variable syntax addresses these inconsistencies as per the following example:

/*** expression syntax ***/
$$foo['bar']['baz']

// PHP 5.x meaning
${$foo['bar']['baz']}

// PHP 7.x meaning
($$foo)['bar']['baz']

/*** expression syntax ***/
$foo->$bar['baz']

// PHP 5.x meaning
$foo->{$bar['baz']}

// PHP 7.x meaning
($foo->$bar)['baz']

/*** expression syntax ***/
$foo->$bar['baz']()

// PHP 5.x meaning
$foo->{$bar['baz']}()

// PHP 7.x meaning
($foo->$bar)['baz']()

/*** expression syntax ***/
Foo::$bar['baz']()

// PHP 5.x meaning
Foo::{$bar['baz']}()

// PHP 7.x meaning
(Foo::$bar)['baz']()

Other than addressing the preceding inconsistencies, several new syntax combinations have been added that make the following expressions now valid:

$foo()['bar']();
[$obj1, $obj2][0]->prop;
getStr(){0}
$foo['bar']::$baz;
$foo::$bar::$baz;
$foo->bar()::baz()
// Assuming extension that implements actual toLower behavior
"PHP"->toLower();
[$obj, 'method']();
'Foo'::$bar;

There are quite a few different syntaxes here. While some of this might seem overwhelming and hard to find use for, it opens a door for new ways of thinking and code use.

Throwables

The exceptions in PHP are not a new concept. They have been around ever since PHP 5 was released. However, they did not encompass all of PHP's error handling because errors were not considered to be exceptions. PHP, at the time, had two-error handling systems. This made it tricky to deal with, as traditional errors were not catchable via the try...catch blocks exceptions. Certain tricks were possible, where one could have used the set_error_handler() function in order to set a user-defined error handler function, basically listening for errors and turning them into exceptions.

Let's look at the following example:

<?php

class Mailer
{
private $transport;

public function __construct(Transport $transport)
{
$this->transport = $transport;
}
}

$transport = new stdClass();

try
{
$mailer = new Mailer($transport);
} catch (\Exception $e) {
echo 'Caught!';
} finally {
echo 'Cleanup!';
}

PHP 5 would not be able to catch this, and instead throws Catchable fatal error, as shown here:

Catchable fatal error: Argument 1 passed to Mailer::__construct() must be an instance of Transport, instance of stdClass given, called in /index.php on line 18 and defined in /index.php on line 6.

By adding the implementation of set_error_handler() before this code, as follows, we could turn that fatal error into an exception:

set_error_handler(function ($errno, $errstr) {
throw new \Exception($errstr, $errno);
});

With the preceding code in place, the try...catch...finally blocks would now kick in as intended. However, there were error types that could not be caught with set_error_handler, such as E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler is called.

The PHP 7 release improved the overall error handling system by introducing the Throwable interface, and moving the errors and exceptions under its umbrella. It is now the base interface for any object that can be thrown via a throw statement. While we cannot extend it directly, we can extend the \Exception and \Error classes. While \Exception is the base class for all PHP and user exceptions, \Error is the base class for all internal PHP errors.

We could now easily rewrite our preceding try...catch...finally block into one of the following:

<?php

// Case 1
try {
$mailer = new Mailer($transport);
} catch (\Throwable $e) {
echo 'Caught!';
} finally {
echo 'Cleanup!';
}

// Case 2
try {
$mailer = new Mailer($transport);
} catch (\Error $e) {
echo 'Caught!';
} finally {
echo 'Cleanup!';
}

Notice the use of \Throwable in the first example catch block. Even though we cannot extend it, we can use it as a shorthand for catching both \Error and \Exception in a single catch statement.

Implementation of \Throwable brings a much needed alignment between errors and exceptions, making them easier to reason with.

Group use declarations

PHP introduced namespaces as part of the 5.3 release. It provided a way to group related classes, interfaces, functions, and constants, thus making our code base more organized and readable. However, dealing with modern libraries usually involves a lot of verbosity in terms of numerous use statements used to import classes from various namespaces, as shown in the following example:

use Magento\Backend\Block\Widget\Grid;
use Magento\Backend\Block\Widget\Grid\Column;
use Magento\Backend\Block\Widget\Grid\Extended;

To address this verbosity, the PHP 7 release introduced the group use declarations, allowing the following syntax:

use Magento\Backend\Block\Widget\Grid;
use Magento\Backend\Block\Widget\Grid\{
Column,
Extended
};

Here, we condensed Column and Extend under a single declaration. We can further condense this using the following compound namespaces:

use Magento\Backend\Block\Widget\{
Grid
Grid\Column,
Grid\Extended
};

The group use declarations act as a shorthand to condense use declarations, making it slightly easier to import classes, constants, and functions in a concise way. While their benefits seem somewhat marginal, their use is completely optional.

Catching multiple exceptions types

With the introduction of throwables, PHP pretty much aligned its efforts around error detection, reporting, and handling. Developers are able to use the try...catch...finally blocks to handle the exceptions as they see fit. The possibility to use multiple catch blocks can give finer control over the response to certain types of exceptions. Sometimes, however, there are groups of exceptions we would like to respond equally. In PHP 7.1, exception handling was further refined to accommodate this challenge.

Let's take a look at the following PHP 5.x example:

try {
// ...
}
catch (\InvalidArgumentException $e)
{
// ...
}
catch (\LengthException $e)
{
// ...
}
catch (Exception $e)
{
// ...
}
finally
{
// ...
}

Here, we are handling three exceptions, two of which are quite specific, and a third one that catches in if the previous two are not matched. The finally block is merely a cleanup, if it happens that one is needed. Imagine now that the same response is needed for both the \InvalidArgumentException and \LengthException blocks. The solution would be to either copy an entire chunk of code from one exception block into another, or, at best, write a function that wraps the response code and then calls that function within each exception block.

The newly added exception handling syntax is enabled to catch multiple exception types. By using a single vertical bar (|), we can define multiple exception types for the catch parameter, as per the following PHP 7.x example:

try {
// ...
}
catch (\InvalidArgumentException | \LengthException $e)
{
// ...
}
catch (\Exception $e)
{
// ...
}
finally
{
// ...
}

Aside from a touch of elegance, the new syntax directly affects code reuse for the better.

Class constant visibility modifiers

There are five types of access modifier in PHP: public, private, protected, abstract, and final. Often called visibility modifiers, not all of them are equally applicable. Their use is spread across classes, functions, and variables, as follows:

  • Functions: public, private, protected, abstract, and final
  • Classes: abstract and final
  • Variables: public, private, and protected

Class constants, however, are not on the list. The older versions of PHP did not allow a visibility modifier on the class constant. By default, class constants were merely assigned public visibility.

The PHP 7.1 release addresses this limitation by introducing the public, private, and protected class constant visibility modifiers, as per the following example:

class Visibility 
{
// Constants without defined visibility
const THE_DEFAULT_PUBLIC_CONST = 'PHP';

// Constants with defined visibility
private const THE_PRIVATE_CONST = 'PHP';
protected const THE_PROTECTED_CONST = 'PHP';
public const THE_PUBLIC_CONST = 'PHP';
}

Similar to the old behavior, class constants declared without any explicit visibility default to public.

Iterable pseudo-type

Quite often, functions in PHP either accept or return an array or object implementing the \Traversable interface. Though both types can be used in the foreach constructs, fundamentally, an array is a primitive type; objects are not. This made it difficult for functions to reason about these types of iterative parameters and return values.

PHP 7.1 addresses this need by introducing the iterable pseudo-type to the mix. The idea is to use it as a type declaration on a parameter or return type to indicate that the value is iterable. The iterable type accepts any array, any object implementing Traversable, and generators.

The following example demonstrates the use of iterable as a function parameter:

function import(iterable $users) 
{
// ...
}

function import(iterable $users = null)
{
// ...
}

function import(iterable $users = [])
{
// ...
}

Trying to pass the value to the preceding import function other than an array instance of Traversable or generator will throw \TypeError. If, however, the default value is assigned, be it null or an empty array, the function will work.

The following examples demonstrates the use of iterable as a function return value:

 function export(): iterable {
return [
'Johny',
'Tom',
'Matt'
];
}

function mix(): iterable {
return [
'Welcome',
33,
4200.00
];
}

function numbers(): iterable {
for ($i = 0; $i <= 5; $i++) {
yield $i;
}
}

One thing to be careful about is that iterable is implemented as a reserved class name in PHP. What this means is that any user class, interface, or trait named iterable will throw an error.

Nullable types

Many programming languages allow some sort of optional or nullable types, depending on terminology. The PHP dynamic type already supports this notion via the built-in null type. A variable is considered to be of the null type if it has been assigned a constant value null, it has not been assigned any value, or it has been unset using the unset() construct. Aside from variables, the null type can also be used against the function parameters, by assigning them a default value of null.

However, this imposed a certain limitation, as we could not declare a parameter that might be null without flagging it as optional at the same time.

PHP 7.1 addressed this limitation by adding a leading question mark symbol (?) to indicate that a type can be null, unless specifically assigned to some other value. This also means that type could be null and mandatory at the same type. These nullable types are now permitted pretty much anywhere where type declarations are permitted.

The following is an example of the nullable type with a mandatory parameter value:

function welcome(?string $name) {
echo $name;
}

welcome(); // invalid
welcome(null); // valid

The first call to the welcome function throws an \Error, because its declaration is making the parameter mandatory. Goes to say that the nullable type should not be mistaken with null being passed as a value.

The following is an example of a nullable type with an optional parameter value, optional in the sense that it has been assigned a default value of null already:

function goodbye(?string $name = null)
{
if (is_null($name))
{
echo 'Goodbye!';
}
else
{
echo "Goodbye $name!";
}
}

goodbye(); // valid
goodbye(null); // valid
goodbye('John'); // valid

The following is an example of function declaration using the nullable return type:

function welcome($name): ?string 
{
return null; // valid
}

function welcome($name): ?string
{
return 'Welcome ' . $name; // valid
}

function welcome($name): ?string
{
return 33; // invalid
}

The nullable types work both with scalar types (Boolean, Integer, Float, String) and compound types (Array, Object, Callable).

Void return types

With all the power of function parameter types and function return types introduced in PHP 7, there was one thing missing from the mix function. While function return types allowed specifying a desired return type, they did not allow specifying the lack of return value. To address this inconsistency, the PHP 7.1 release introduced a void return type feature.

Why is this important, we might ask ourselves? As with previously mentioned function return types, this feature can be extremely useful for documentation and error-checking purposes. By its nature, PHP does not require a return statement in its function definitions, making it unclear at first look if the function simply executes certain actions or returns a value. Using the void return type makes it clearer that a function's purpose is to perform an action, rather than producing a result.

Let's take a look at the following example:

function A(): void {
// valid
}

function B(): void {
return; // valid
}

function C(): void {
return null; // invalid
}

function D(): void {
return 1; // invalid
}

The function A and function B methods showcase a valid use of the void type parameter. The  function A method has no explicitly set return value, but that's OK, as PHP implicitly always returns null. The function B method simply uses the return statement without any following type, which also makes it valid. The function C method is a bit strange, as it looks like it might be valid at first, but it's not. How is it that function C is invalid while the function A method is, even though they do the same thing? Even though return and return null are technically equivalent in PHP, they are not really the same. The existence of a return type, or its lack, denotes a function intent. Specifying return values, even if its null, suggests the value is significant. With a void return type, the return value is insignificant. The use of the void return type, therefore, signifies an unimportant return value, the one that won’t be used anywhere after the function is called.

The differentiation between explicit void and implicit null return might come as somewhat foggy. The takeaway here is that using void return types conveys that the function is not supposed to return any kind of value. While they do not make any major impact on the code itself, and their use is fully optional, they do bring a certain richness to the language.

Summary

The PHP 7 and 7.1 releases have introduced quite a few changes. Some of these changes transform the language beyond what PHP once was. While still pertaining the dynamic typing system, function parameters and return types can now be strictly defined. This changes the way we look and work with functions. Among function-related changes, there are several others targeting improvements over a decade old PHP 5. The ecosystem, as a whole, will take some time to catch up. For developers with experience in PHP 5, these changes are not merely technical in nature; they require change of mindset in order to successfully apply what is now possible.

Moving forward, we will look into the current state of PHP standards, who defines them, what they describe, and how can we benefit from embracing them.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Leverage the newest tools available in PHP 7 to build scalable applications
  • Embrace serverless architecture and the reactive programming paradigm, which are the latest additions to the PHP ecosystem
  • Explore dependency injection and implement design patterns to write elegant code

Description

PHP is a server-side scripting language that is widely used for web development. With this book, you will get a deep understanding of the advanced programming concepts in PHP and how to apply it practically The book starts by unveiling the new features of PHP 7 and walks you through several important standards set by PHP Framework Interop Group (PHP-FIG). You’ll see, in detail, the working of all magic methods, and the importance of effective PHP OOP concepts, which will enable you to write effective PHP code. You will find out how to implement design patterns and resolve dependencies to make your code base more elegant and readable. You will also build web services alongside microservices architecture, interact with databases, and work around third-party packages to enrich applications. This book delves into the details of PHP performance optimization. You will learn about serverless architecture and the reactive programming paradigm that found its way in the PHP ecosystem. The book also explores the best ways of testing your code, debugging, tracing, profiling, and deploying your PHP application. By the end of the book, you will be able to create readable, reliable, and robust applications in PHP to meet modern day requirements in the software industry.

Who is this book for?

This book is for intermediate level developers who want to become a master of PHP. Basic knowledge of PHP is required across areas such as basic syntax, types, variables, constants, expressions, operators, control structures, and functions.

What you will learn

  • Grasp the current state of PHP language and the PHP standards
  • Effectively implement logging and error handling during development
  • Build services through SOAP and REST and Apache Trift
  • Get to know the benefits of serverless architecture
  • Understand the basic principles of reactive programming to write asynchronous code
  • Practically implement several important design patterns
  • Write efficient code by executing dependency injection
  • See the working of all magic methods
  • Handle the command-line area tools and processes
  • Control the development process with proper debugging and profiling
Estimated delivery fee Deliver to Finland

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jun 27, 2017
Length: 536 pages
Edition : 1st
Language : English
ISBN-13 : 9781785882814
Languages :
Concepts :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Finland

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Publication date : Jun 27, 2017
Length: 536 pages
Edition : 1st
Language : English
ISBN-13 : 9781785882814
Languages :
Concepts :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 110.97
Mastering PHP 7
€36.99
PHP 7 Data Structures and Algorithms
€36.99
PHP Microservices
€36.99
Total 110.97 Stars icon
Banner background image

Table of Contents

17 Chapters
The All New PHP Chevron down icon Chevron up icon
Embracing Standards Chevron down icon Chevron up icon
Error Handling and Logging Chevron down icon Chevron up icon
Magic Behind Magic Methods Chevron down icon Chevron up icon
The Realm of CLI Chevron down icon Chevron up icon
Prominent OOP Features Chevron down icon Chevron up icon
Optimizing for High Performance Chevron down icon Chevron up icon
Going Serverless Chevron down icon Chevron up icon
Reactive Programming Chevron down icon Chevron up icon
Common Design Patterns Chevron down icon Chevron up icon
Building Services Chevron down icon Chevron up icon
Working with Databases Chevron down icon Chevron up icon
Resolving Dependencies Chevron down icon Chevron up icon
Working with Packages Chevron down icon Chevron up icon
Testing the Important Bits Chevron down icon Chevron up icon
Debugging, Tracing, and Profiling Chevron down icon Chevron up icon
Hosting, Provisioning, and Deployment Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.7
(7 Ratings)
5 star 85.7%
4 star 0%
3 star 14.3%
2 star 0%
1 star 0%
Filter icon Filter
Top Reviews

Filter reviews by




mario a torre fuentelzas Dec 20, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Rapidez
Amazon Verified review Amazon
Maksym Jun 29, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
The book describes the new features of PHP 7.This is not a book that you can use to teach yourself PHP 'from scratch', so you should have knowledge of the previous PHP versions.
Amazon Verified review Amazon
Cliente de Amazon Jul 13, 2019
Full star icon Full star icon Full star icon Full star icon Full star icon 5
One of the best books about PHP 7, contain very useful information, many topics in the book are just introductions but give you the vision of what subjects you need to dig more to be come a professional in PHP. If you already know how to code in PHP but want to be more proficient and know the technologies necessary for that, this book is for you.
Amazon Verified review Amazon
Vitor Adonai Arruda Barbosa Nov 10, 2017
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Esse livro é por tópicos, não existe um projeto final. Mas realmente, é bom!
Amazon Verified review Amazon
Lawrence Aug 19, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
It is a good book. It goes over a verity of topics and really insightful.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela