PHP Pandas: PHP7

Before the end of the year it's likely that we'll see the release of PHP7. With it being a major release of PHP it will arrive with a fully-stocked toy-box for us to experiment with. However, if that's not enough to tickle your tastebuds, then it's also worth noting that PHP7 has been benchmarked at executing code up to twice as fast as previous builds of PHP. That's a speed increase that we just can't turn down!

I had originally considered updating the book to begin with PHP7, however, I think there will still be many people using PHP5 for a year or so. Therefore, I have instead decided to create a separate chapter.

Let's dive into the world of PHP7!

Installation

This is a bit tricky at the moment! You see, at the time of writing this chapter PHP7 has yet to be released. Third-party package channels are distributing the release candidate of the new version, but if you're not confident with using trusted third party sources then I'd stick with PHP5 until the new version is released. Once the final version has been released, I'll come back to update this chapter.

Wait. Where's PHP6?

Great question! It's been lurking in the same place as Windows 9, unfortunately.

Simply put, there was a version of PHP known as PHP6, but it never made its way to commercial use. To avoid confusion, the PHP internals team decided to use version 7 as the next release milestone for the project. This means that there will never be a true PHP 6.

If you'd like to read more about the reasoning, I'd suggest taking a look at the PHP 6 vs 7 RFC where a vote was cast to decide upon the version number for the latest iteration of the language.

Return Type Declarations

Now then, let's get to the meat and potatoes, shall we? This new feature is without a doubt my favourite. I know, I know. I'm meant to build up the suspense and tell you about my favourite feature at the end, but I simply can't wait!

In the more recent versions of PHP, functions and methods were able to return values of any type that they wished. PHP is a loosely-typed language, and as such we have the option of returning whatever variable type pleases us!

Don't panic! This is still possible in PHP7. However, we now have the option to be a little smarter about how our functions and methods will return values. I think this is a great place to note that the PHP internals team have done a wonderful job of keeping PHP7 highly backward compatible. You don't have to use the features mentioned in this chapter, but I promise that you'll want to!

Let's take a look at a new way of defining a function in PHP7.

<?php

function pandaSeven() : int {
    return 3;
}

Holy moly, would you take a look at that! A whole new format. Shall we take a look at the method equivalent?

<?php

class Panda
{
    public function roar() : string {
        return 'Mew!';
    }
}

Beautiful!

You see, by including a : colon and a variable type, we've told PHP that the function that we've defined must return a value of the defined type. This means that the examples above will work just fine, but let's take a look at another function.

<?php

class Panda
{
    public function roar() : string {
        return 4.5;
    }
}

$panda = new Panda;

var_dump($panda->roar());

In the above example, the return type of the roar() method is defined as a string, but if you look very closely, you'll notice that we're returning a float value instead!

What do you think will happen if we execute the code snippet above? Let's find out!

string(3) "4.5"

Well, that's not so dramatic is it? You see, PHP knows that our method must return a string, and it's fully capable of casting a float to a string, so that's what it does before returning it.

In fact, any type which PHP can cast, will be corrected when the value is returned.

Let's try something a little more interesting, shall we? It would be difficult for PHP to cast an array of integers to a string, so let's attempt that! Here's the example.

<?php

class Panda
{
    public function roar() : string {
        return [3, 5];
    }
}

$panda = new Panda;

var_dump($panda->roar());

Perfect! Let's execute the snippet to see how PHP7 copes in this sithation.

Fatal error: Uncaught TypeError: Return value of Panda::roar() must be of the type string, array returned in <file>:7

Interesting! PHP doesn't know how to cast that value to a string, but we've told the language that the method must return a string. There's simply no other option but to throw an error!

Earlier, we saw how PHP will cast a float to a string to fulfill the requirements of the return type declaration. What if we don't want this functionality? In fact, many other 'strict' languages won't cast for you. They'll simply throw an error if the return type is incorrect.

Fortunately, this is also possible with PHP7, but we must first enforce 'strict' type checking.

You may only enable strict type checking on a file-by-file basis. This means, that you'll have to enable it for every file in which you'd like to use strict types.

To use strict types, the following declaration must be the first snippet of PHP code to appear after the opening <?php language brace. For example...

<?php declare(strict_types = 1);

class Panda
{
    public function roar() : string {
        return 3.5;
    }
}

$panda = new Panda;

var_dump($panda->roar());

Here, we've placed declare(strict_types = 1); on the first line of the file, so we can be sure that PHP isn't going to try and be clever about return types. Our method should return a string, but we're returning a float. What do you think will happen?

Fatal error: Uncaught TypeError: Return value of Panda::roar() must be of the type string, float returned in <file>:6

Wunderbar! No more mister smartypants PHP!

So I wonder, why is this feature useful? I mean, we could just be extra careful about our return types, couldn't we?

In truth, the feature isn't all that useful by itself, but when used with an interface or abstract class, new possibilities present themselves!

In a previous chapter, we explained how defining our method signatures in an interface or abstract class, will build trust with classes which implement/extend them. Well, the return type declaration is also part of the method signature.

This means that if we have an interface, for example.

<?php

interface BambooEater
{
    public function roar() : string;
}

We know that any class which implements this interface and the roar() method must return a string. Thus, we will not have to check the type of the value returned before using it. Yet another contract has been made.

You can declare the return type of a function or method to be of any scalar or non-scalar type, including classes. This also means that you can set the return type to be of a specific interface, and experience polymorphism within the implementations returned from the function!

Exciting stuff! I'm keen to see what this new feature will bring to the world of PHP.

Scalar Type Declarations

In a previous chapter, I warned you that type-hinting methods and functions with scalar types (int, string, etc) was impossible? Great, forget that!

With PHP7 you can type hint... ANYTHING.

Excited? I know you are!

<?php

function pandaSeven(int $seven, string $lushui) {
    return $seven;
}

This is perfectly valid with PHP7.

It's worth noting that as with return type declarations, PHP will attempt to cast a value into the defined type. Once again, using the declare(strict_types = 1); strict type declaration will cease this behaviour, and cause an error to occur instead!

Null Coalesce Operator

In previous versions of PHP, we'd often find ourselves doing something similar to the following.

<?php

if (isset($panda)) {
    echo $panda;
} else {
    echo 'Giant Panda';
}

// or...

echo isset($panda) ? $panda : 'Giant Panda';

This is because we don't want to attempt to access a variable that is not set. We really don't want an error on our hands. We also don't want it to be null.

In PHP7, we have the Null Coalesce ?? Operator, which looks like this.

<?php

echo $panda ?? 'Giant Panda';

If the value to the left of the ?? doesn't exist, or is null, then the statement will use the value to the right of the operator. Nice and short, isn't it?

Not only that, but you can stack as many of these operators into a statement as you desire. For example.

<?php

echo $first ?? $second ?? $third ?? $fourth ?? 'fifth';

Here, PHP7 will work its way from left to right using the first value which is valid. I'm sure that this feature will become part of your toolkit in no time at all!

Spaceship Operator

Ground control to Major Tom...

The spaceship operator makes it really simple to compare values. Let's take a look at an example.

<?php

$tom = 3 <=> 4;

As you can see, the spaceship <=> operator (and yes, that's the real name) looks like a spaceship. Clearly. Shouldn't it be called the UFO operator?

Anyhow, in the above example the value of $tom will be set to -1. This is because 3 is less than 4. Let's take a look at the possible values.

$a > $b : +1
$a = $b :  0
$a < $b : -1

This format of the resulting value is useful. This is because many of PHP's native sorting functions use the format to determine the order of values.

Define Constant Arrays

We've discovered how to define global constants in a previous chapter. For example.

<?php

define('PANDA', 'Awesome!');

Well, in PHP7 you can also define constants that are arrays. Here's an example.

<?php

define('PANDA', ['Awesome!', 'Great!', 'Fluffy!']);

echo PANDA[0];

It's that simple! Well what did you expect? Not all of the features are going to be major, are they!?

Anonymous Classes

Anonymous classes are classes without names. Surprised? No? Oh, ok..

Here's an example.

<?php

$panda->eat(new class {
    public function noise()
    {
        return 'Crunch!';
    }
});

In the above example, we're passing an anonymous class into a function. See? It has no name!

Anonymous classes are useful for when you don't need to keep a reference (assignment to a variable) to the class. These types of classes are extremely useful when combined with unit testing, which is a concept that will be covered in a future title!

Group Use Declarations

Finally, let's take a look at Group Use Declarations.

Previously, to use multiple classes held within the same namespace we'd have to use them separately, like this.

<?php

namespace OtherNamespace;

use Animal\Panda\Red;
use Animal\Panda\Giant;
use Animal\Panda\Fluffy;

In PHP7, you've got another option. Here's an example.

<?php

namespace OtherNamespace;

use Animal\Panda\{Red, Giant, Fluffy};

The effect is identical, but you've saved yourself a few keystrokes. It's worth noting that you can still use class aliases within the group { use } brackets. For example.

<?php

namespace OtherNamespace;

use Animal\Panda\{Red as Lushui, Giant, Fluffy};

While some will prefer to use this format. I would actually encourage the use of the 'older' method of using multiple classes within the same namespace. You see, if using a version control system, it will be much easier to determine whether a class is removed, or to commit a change without occurring conflicts with team-workers code. I also think it's much clearer to read!

We've not covered version control in this title, so don't panic if the above statement doesn't make sense! Use whichever format works well for you. It's great to have options!