Getting the Most Out of PHP7 Types 🐘

In the latest versions of PHP, improvements have been introduced regarding type support. Although we are shocked by it being the last day of the 3x1 promotion for CodelyTV Pro, in this video we will see how to take advantage of it. At the end of the post, you have the instructions to enter the raffle for a ticket to Polycon!

Dynamic Types

A language is dynamically typed when it deduces the data type of variables and we do not have to indicate it. In the following example, we see how PHP would deduce the resulting type from adding an int and a string that contains an integer:

var_dump(1 + "1"); // Output: int(2)

Being dynamically typed and interpreted, PHP does not have a compilation process; rather, it is at runtime when PHP validates whether a certain variable has a certain method or not. This is known as Duck Typing:

function greeting($from, $to)
{
    return $from->name() . " says hello to " . $to->name();
}

echo greeting("Rafa", "Javi"); // Output \*at run-time\*: Fatal error: Uncaught Error: Call to a member function name() on string

final class Person
{
    private $name;

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

    public function name()
    {
        return $this->name;
    }
}

$rafa = new Person("Rafa");
$javi = new Person("Javi");

echo greeting($rafa, $javi); // Output: Rafa says hello to Javi

That said, let's take a look at the evolution of PHP regarding types:

Type Declaration (previously called Type Hinting)

Starting from PHP 5.0, we have the ability to specify the data type that a certain variable contains when received as an argument. This brings some robustness to our method contracts and leaves behind the possibility of Duck Typing as we saw before: Despite being an advance, it still had its limitations: Only classes or interfaces could be specified, not primitive types of the language.

  • PHP 5.1 introduced the ability to specify array as input type
  • PHP 5.4 introduced support for callable, allowing us to ensure that we received a first-class function and no value
  • PHP 7.0 introduced support for primitives like bool, string, int, and float
  • PHP 7.1 introduced support for iterable, understanding that it accepts both Traversable implementations and primitive arrays

So, we can refactor the previous function to something like:

function greeting(Person $from, Person $to)
{
    return $from->name() . " says hello to " . $to->name();
}

echo greeting("Rafa", "Javi"); // Output \*at run-time\*: Fatal error: Uncaught TypeError: Argument 1 passed to greeting() must be an instance of Person, string given

$rafa = new Person("Rafa");
$javi = new Person("Javi");

echo greeting($rafa, $javi); // Output: Rafa says hello to Javi

Return Type

PHP 7.0 introduces the ability to add return types in our functions, finally giving them the robustness they deserve. Now we can declare interfaces that explicitly express all the necessary information for implementations, and the clients of these interfaces will have all the necessary information:

function greeting(Person $from, Person $to): string
{
    return $from->name() . " says hello to " . $to->name();
}

Furthermore, PHP 7.1 introduces the option to specify void as a return type. This way, we can explicitly indicate that a certain function does not return any value and, therefore, that function aims to produce a side-effect like the examples we discussed in the video. Even today, we must indicate the exceptions that can be thrown by a method through documentation, while in other languages, they can be specified as part of the contract as well (Java annotations).

Strict Types

Another functionality regarding types incorporated in PHP 7.0 is the declare(strict_types=1); statement. This statement prevents automatic casting that PHP performs if this statement is not specified:

<?php

function greeting(string $fromName, string $toName): string
{
    return $fromName . " says hello to " . $toName;
}

echo greeting("Rafa", 123); // Output: Rafa says hello to 123

As we see below, if we specify this statement, even though there is a casting available from int(123) to string("123"), PHP does not perform it and throws a Fatal error:

<?php

declare(strict_types=1);

function greeting(string $fromName, string $toName): string
{
    return $fromName . " says hello to " . $toName;
}

echo greeting("Rafa", 123); // Output: Fatal error: Uncaught TypeError: Argument 2 passed to greeting() must be of the type string, integer given

Ideally, strict type declaration would have been able to declare it at the project level. However, since defining something like this in php.ini would affect the code of our dependencies, they preferred to be conservative and define it at the project level. Despite this, considering the maturity of Composer in the PHP ecosystem, it might have been beneficial to declare it within composer.json, or to keep it separate in a specific file like strict_types.json, which would allow setting exclusion rules based on directories. In any case, this is not the case. Hence, we recommend that you modify the “New PHP Class” template of your IntelliJ/PhpStorm to include this declaration by default.

Nullable Type

PHP 7.1 introduces the ability to explicitly specify that a certain type can be null. This works very well for the practical cases we discussed in the video, but following the example of the post, it would allow things like:

<?php

declare(strict_types=1);

function greeting(string $fromName, ?string $toName): ?string
{
    if (is_null($toName)) {
        return null;
    }

    return $fromName . " says hello to " . $toName;
}

echo greeting("Rafa", "Javi"); // Output: Rafa says hello to Javi
echo greeting("Rafa", null); // Output: "" (empty)
echo greeting(null, "Javi"); // Output: Fatal error: Uncaught TypeError: Argument 1 passed to greeting() must be of the type string, null given

Conclusion on Types and PHP

As we have seen, the evolution of type support in PHP from version 5 to 7.1 has been remarkable. Although this does not represent any improvement over the functionalities available in other languages, it at least updates and modernizes the language to allow a programming style with which, at least we, feel much more comfortable 🙂 Lastly, I remind you that today is the last day to take advantage of the 3x1 offer for Codely TV Pro. The course platform of CodelyTV 🤓

Raffle for Polycon 2017 Ticket 🎟️🎯🐘

On October 6th and 7th, the Polycon Software Engineering Conference will take place in Barcelona. This is a language-agnostic conference being held for the first time this year and already features top international speakers. Topics will range from Hexagonal Architecture to Event Sourcing, passing through Microservices, news from Symfony 4, graph databases like Neo4j, and much more. For more information, you can visit the official Polycon website. They are really good people and they have generously given us a ticket to raffle among CodelyTV followers, so you just need to follow 3 simple steps to enter the raffle:

With this, you will enter the raffle for a ticket valued at €84, and on Tuesday, September 19th, we will announce the winner. Good luck! 🙂

Pay according to your needs

lite (only monthly)

19 €
per month
  • Access to a subset of courses to lay the foundation for maintainable, scalable, and testable code
  • Company invoice
Popular

standard

24,92 €
Save 121
Annual payment of 299
per month
  • Full course catalog
  • Design and architecture challenges
  • Highlighted solutions videos for challenges
  • Receive job offers verified by Codely
  • Company invoice

premium

41,58 €
Save 89
Annual payment of 499
per month
  • All previous benefits
  • Early access to new courses
  • More benefits coming soon

We won’t increase the price while your subscription is active