PHP OOP - Recap 1: inheritance and type safety

Last revision:

Overview

Before we get into polymorphism, let's review a few core concepts.

Object Orientation

Object Orientation is all about writing code that uses objects that represent things. 

Inheritance

Inheritance is a mechanism that lets you define classes that inherit their properties and methods from their parent class, their parent's parent class, and so on.

Inheritance is one of several approaches you can use to reuse code: you define common behaviour (methods) and data (properties) once in a parent class, and then you fine-tune your child classes by adding or overriding certain methods and properties.

Any change to a parent class will then automatically apply to all child classes.

A class can only inherit from one parent class (multiple inheritance is not supported in PHP), but the parent class can inherit from their parent class, and so on.

Type safety

PHP is a loosely typed language: it supports data types such string, integer, float, and array but doesn't require you to declare the type of each variable you use. PHP figures out a variable's type based on the value and how you use it.

As a result, when you create a function or method that accepts parameters, you're never entirely certain to receive the types of data you expect.

For instance, if you call the following method intended to sum up 2 numbers, and pass along two strings instead of two integers, PHP will throw an error during execution:

Code
<?php

function sum($a, $b) {
  return $a + $b;
}

// This will throw an error!
$result = sum("hello", "world");

print($result . PHP_EOL);

Output:

TypeError: Unsupported operand types: string + string

This error is produced because we try to add one string to another, which is not supported by PHP.

One solution to make code more robust and guard against unexpected data types being sent to your functions and methods is enabling strict mode by and using type hints.

Type hints

Type hints let you specify which exact data types your functions, methods, and properties expect. That way the PHP engine knows more about your intentions, and static analysis tools like PHPStan can verify the type safety of your code without actually executing it - in other words: before the end users see any errors.

A type-safe version of the sum() example looks like this:

Code
<?php

declare(strict_types=1);

function sum(int $a, int $b): int {
 return $a + $b;
}

// This will throw an error!
$result = sum("hello", "world");

print($result . PHP_EOL);

Output:

TypeError: sum(): Argument #1 ($a) must be of type int, string given

While still an error message, we're in a better situation:

  • PHP detected that we're calling sum() with the wrong type of arguments.
  • PHP tells us what is expected and what is actually used
  • sum() is never actually executed: execution of the script stopped the moment we tried to call sum() with the wrong type of arguments. This is different from the previous example where PHP entered into the sum() function and attempted to actually execute "hello" + "world" resulting in an error.

And of course we could have prevented any error from occurring by running a static analysis tool that would have told us about this problem without running the code.

We'll discuss how to set up and use PHPStan, the leading PHP static analysis tool, later.

Type hinting with your own types

Type hinting is not restricted to the so-called primitive types (int, string, array, object, ...). The classes you define are also types you can use:

Code
<?php

class Dog {
  public string $name;
  public string $breed;
}

function printDog(Dog $dog) {
  print("My dog is a {$dog->breed} named {$dog->name}.");
}

$mydog = new Dog();
$mydog->name = "Rex";
$mydog->breed = "German shepherd";

printDog($mydog);

This is nice because you don't need to manually make sure that the incoming parameter is really an instance of the Dog class, and that the properties breed and name really exist.

And, of course, attempting to call printDog() and passing along anything other than a Dog object as parameter will result in a TypeError.

Summary

  • Object Orientation is about writing code that uses objects that represent things. 
  • Inheritance is a mechanism whereby a class can inherit methods and properties from a parent class.
  • Type safety is the practice of using type hints to enforce strict data types to increase the robustness of your code, and allow for fewer "surprises" when your code has to deal with data of an unexpected type.