Book Image

PHP 8 Programming Tips, Tricks and Best Practices

By : Doug Bierer
Book Image

PHP 8 Programming Tips, Tricks and Best Practices

By: Doug Bierer

Overview of this book

Thanks to its ease of use, PHP is a highly popular programming language used on over 78% of all web servers connected to the Internet. PHP 8 Programming Tips, Tricks, and Best Practices will help you to get up-to-speed with PHP 8 quickly. The book is intended for any PHP developer who wants to become familiar with the cool new features available in PHP 8, and covers areas where developers might experience backward compatibility issues with their existing code after a PHP 8 update. The book thoroughly explores best practices, and highlights ways in which PHP 8 enforces these practices in a much more rigorous fashion than its earlier versions. You'll start by exploring new PHP 8 features in the area of object-oriented programming (OOP), followed by enhancements at the procedural level. You'll then learn about potential backward compatible breaks and discover best practices for improving performance. The last chapter of the book gives you insights into PHP async, a revolutionary new way of programming, by providing detailed coverage and examples of asynchronous programming using the Swoole extension and Fibers. By the end of this PHP book, you'll not only have mastered the new features, but you'll also know exactly what to watch out for when migrating older PHP applications to PHP 8.
Table of Contents (17 chapters)
1
Section 1: PHP 8 Tips
6
Section 2: PHP 8 Tricks
11
Section 3: PHP 8 Best Practices

Improving code using typed properties

In the first section of this chapter, Using constructor property promotion, we discussed how data types can be used to control the type of data supplied as arguments to functions or class methods. What this approach fails to do, however, is guarantee that the data type never changes. In this section, you will learn how assigning a data type at the property level provides stricter control over the use of variables in PHP 8.

What are typed properties?

This extremely important feature was introduced in PHP 7.4 and continues in PHP 8. Simply put, a typed property is a class property with a data type preassigned. Here is a simple example:

// /repo/ch01/php8_prop_type_1.php
declare(strict_types=1)
class Test {
    public int $id = 0;
    public int $token = 0;
    public string $name = '';
}
$test = new Test();
$test->id = 'ABC';

In this example, if we attempt to assign a value representing a data type other than int to $test->id, a Fatal error is thrown. Here is the output:

Fatal error: Uncaught TypeError: Cannot assign string to property Test::$id of type int in /repo/ch01/php8_prop_type_1.php:11 Stack trace: #0 {main} thrown in /repo/ch01/php8_prop_type_1.php on line 11 

As you can see from the preceding output, a Fatal error is thrown when the wrong data type is assigned to a typed property.

You have already been exposed to one form of property typing: constructor property promotion. All properties defined using constructor property promotion are automatically property typed!

Why is property typing important?

Typed properties is part of a general trend in PHP first seen in PHP 7. The trend is toward making language refinements that restrict and tighten the use of your code. This leads to better code, which means fewer bugs.

The following example illustrates the danger of relying solely upon property-type hinting to control the data type of properties:

// /repo/ch01/php7_prop_danger.php
declare(strict_types=1);
class Test {
    protected $id = 0;
    protected $token = 0;
    protected $name = '';
    public function __construct(
        int $id, int $token, string $name) {
        $this->id = $id;
        $this->token = md5((string) $token);
        $this->name = $name;
    }
}
$test = new Test(111, 123456, 'Fred');
var_dump($test);

In the preceding example, notice in the __construct() method that the $token property is accidentally converted to a string. Here is the output:

object(Test)#1 (3) {
  ["id":protected]=>  int(111)
  ["token":protected]=>
  string(32) "e10adc3949ba59abbe56e057f20f883e"
  ["name":protected]=>  string(4) "Fred"
}

Any subsequent code expecting $token to be an integer might either fail or produce unexpected results. Now, have a look at the same thing in PHP 8 using typed properties:

// /repo/ch01/php8_prop_danger.php
declare(strict_types=1);
class Test {
    protected int $id = 0;
    protected int $token = 0;
    protected string $name = '';
    public function __construct(
        int $id, int $token, string $name) {        
        $this->id = $id;
        $this->token = md5((string) $token);
        $this->name = $name;
    }
}
$test = new Test(111, 123456, 'Fred');
var_dump($test);

Property typing prevents any change to the preassigned data type from occurring, as you can see from the output shown here:

Fatal error: Uncaught TypeError: Cannot assign string to property Test::$token of type int in /repo/ch01/php8_prop_danger.php:12

As you can see from the preceding output, a Fatal error is thrown when the wrong data type is assigned to a typed property. This example demonstrates that not only does assigning a data type to a property prevent misuse when making direct assignments, but it also prevents misuse of the property inside class methods as well!

Property typing can lead to a reduction in code

Another beneficial side effect of introducing property typing to your code is a potential reduction in the amount of code needed. As an example, consider the current practice of marking properties with a visibility of private or protected, and then creating a series of get and set methods to control access (also called getters and setters).

Here is how that might appear:

  1. First, we define a Test class with protected properties, as follows:
    // /repo/ch01/php7_prop_reduce.php
    declare(strict_types=1);
    class Test {
     protected $id = 0;
     protected $token = 0;
     protected $name = '';o
  2. Next, we define a series of get and set methods to control access to the protected properties, as follows:
        public function getId() { return $this->id; }
        public function setId(int $id) { $this->id = $id; 
        public function getToken() { return $this->token; }
        public function setToken(int $token) {
            $this->token = $token;
        }
        public function getName() {
            return $this->name;
        }
        public function setName(string $name) {
            $this->name = $name;
        }
    }
  3. We then use the set methods to assign values, as follows:
    $test = new Test();
    $test->setId(111);
    $test->setToken(999999);
    $test->setName('Fred');
  4. Finally, we display the results in a table, using the get methods to retrieve property values, as follows:
    $pattern = '<tr><th>%s</th><td>%s</td></tr>';
    echo '<table width="50%" border=1>';
    printf($pattern, 'ID', $test->getId());
    printf($pattern, 'Token', $test->getToken());
    printf($pattern, 'Name', $test->getName());
    echo '</table>';

Here is how that might appear:

Table 1.4 – Output using Get methods

Table 1.4 – Output using Get methods

The main purpose achieved by marking properties as protected (or private) and by defining getters and setters is to control access. Often, this translates into a desire to prevent the property data type from changing. If this is the case, the entire infrastructure can be replaced by assigning property types.

Simply changing the visibility to public alleviates the need for get and set methods; however, it does not prevent the property data from being changed! Using PHP 8 property types achieves both goals: it eliminates the need for get and set methods and also prevents the data type from being accidentally changed.

Notice here how much less code is needed to achieve the same results in PHP 8 using property typing:

// /repo/ch01/php8_prop_reduce.php
declare(strict_types=1);
class Test {
    public int $id = 0;
    public int $token = 0;
    public string  $name = '';
}
// assign values
$test = new Test();
$test->id = 111;
$test->token = 999999;
$test->name = 'Fred';
// display results
$pattern = '<tr><th>%s</th><td>%s</td></tr>';
echo '<table width="50%" border=1>';
printf($pattern, 'ID', $test->id);
printf($pattern, 'Token', $test->token);
printf($pattern, 'Name', $test->name);
echo '</table>';

The preceding code example shown produces exactly the same output as the previous example and also achieves even better control over property data types. Using typed properties, in this example, we achieved a 50% reduction in the amount of code needed to produce the same result!

Tip

Best practice: Use typed properties whenever possible, except in situations where you explicitly want to allow the data type to change.