PHP was considered as the weakly typed language before the release of PHP 7. As PHP is moving forward, it's focusing more on type safety. Now we can define the data type of a variable while declaring it. It makes it much easier to identify the type of values that a variable can have. Also, this new feature introduced in PHP 7.4 does not break existing code, hence making it easy to migrate from previous versions. The rest of the sections of this tutorial explains the usage of property types in PHP.
Typed Property Rules
This section clears the usage of typed properties. We can use typed properties only if below-listed conditions are met.
- The PHP version is at least PHP 7.4
- Typed properties are only allowed in classes
- The typed properties must be used only with access modifiers including var, public, protected and private
- We can use all types including Class Type except void and callable
Example Code
This section provides an example of a class using typed properties. It shows that the appropriate types are defined for all the properties of the Class Vehicle while declaring them.
abstract class Vehicle {
public int $id;
public string $name;
public string $color;
public string $bodyType;
public float $fuelCapacity;
public int $numberOfDoors; }
class Car extends Vehicle {
public bool $roofLoad; }
We can see that the type int is used for the property id. It means that the id property can only be assigned with integer values. It will throw an exception in case any other type of value is assigned to id. This ensures that the object properties are assigned with the relevant values. It will also avoid functions like is_int() to check the type of values.
Type Of Types
We can use the below-listed types for typed properties. Using void and callable as property type is not allowed.
- int - Integers
- float - Floating point numbers
- bool - Booleans
- string - Strings
- array - Arrays
- iterable - A shortcut for array | Traversable
- object -Objects
- ?<type> - Nullable
- self - Self
- parent - Parent
- <Class> - Classes
- <Interface> - Interfaces
Uninitialized State
A new variable state i.e. uninitialized is introduced with typed properties. If we try to access the property without initializing it, Fatal error will be thrown as shown below.
$car = new Car();
echo $car->numberOfDoors;
// Result:
Fatal error: Uncaught Error: Typed property Car::$numberOfDoors
must not be accessed before initialization
We can avoid such errors by initializing the propery as shown below.
$car = new Car();
$car->numberOfDoors = 4;
echo $car->numberOfDoors;
Below listed are the rules of uninitialized typed properties.
- The uninitialized typed properties cannot be accessed as shown above
- We can create objects having uninitialized properties since the check will be made while accessing the property
- We must assign appropriate value to the typed properties before accessing it
- We can use the keyword unset to uninitialized the typed properties
Default Values
We can also assign the default values to the properties while declaring them as shown below.
abstract class Vehicle {
public int $id; // No default value, it must be initialized before accessing it
public ?string $name = null; // Only null value is allowed for nullable
public string $color = 'Black'; // The default color
public string $bodyType; // No default value
public float $fuelCapacity = 16.85; // Default float value
public int $numberOfDoors = 2; // Default integer value }
class Car extends Vehicle {
public string $bodyType = 'Sedan'; // Default string value
public bool $roofLoad = false; // Default boolean value }
The default values are not allowed for the types including object, classes, and interfaces.
Static Properties
We can also define the type of static properties as shown below.
class Car extends Vehicle {
public static int $count; // Typed static variable
public bool $roofLoad; }
Constructors
We can use the constructors to assign the default values to the properties as shown below.
class Driver {
public string $name;
public function __construct(string $name) {
$this->name = $name; // Initializing string property } }
abstract class Vehicle {
public int $id;
public string $name;
public string $color;
public string $bodyType;
public float $fuelCapacity;
public int $numberOfDoors;
public function __construct(int $id, string $name) {
$this->id = $id; // Initializing integer property
$this->name = $name; // Initializing string property }
}
class Car extends Vehicle {
public bool $roofLoad;
public Driver $driver;
public function __construct(int $id, string $name, string $bodyType, string $driverName) {
parent::__construct($id, $name);
$this->bodyType = $bodyType; // Initializing boolean property
$this->driver = new Driver($driverName); // Initializing class property }
}
// Example
$car = new Car(1125, 'Chevrolet', 'A Body', 'Rick');
echo "Id: " . $car->id;
echo "Driver: " . $car->driver->name;
This is how we can initialize the properties using constructors.
Inheritance
Most of the object-oriented programming languages including Java allows changing the type in child classes which is not true with PHP 7.4 as of now. The below-mentioned example clears it.
class Driver {
public string $name; }
class TrainedDriver extends Driver {
public string $institute; }
abstract class Vehicle {
public int $id;
public string $name;
public string $color;
public string $bodyType;
public float $fuelCapacity;
public int $numberOfDoors;
public Driver $driver;
}
class Car extends Vehicle {
public string $bodyType = 'Sedan'; // It's absolutely fine since the type is same
public TrainedDriver $driver; // Not valid since type changed
public bool $roofLoad;
}
In the above example, though TrainedDriver is also Driver, but the change in type is not allowed in child classes.
Type Coercion and Strict Types
PHP tries to convert the values where possible as shown below.
// The string will be auto-convered to integer value $car->id = '1231';
We can also disable this behavior as shown below.
declare(strict_types=1);
...
...
$car->id = '1231';
// It will throw error
Fatal error: Uncaught TypeError:
Typed property Car::$id must be int, string used
Type Hint
With the introduction of typed properties, there is no need to add comments for type hinting as shown below.
// Class without typed properties class Foo {
/** @var int $id */ private $id;
/** @var string $name */
private $name; }
// Class with typed properties class Foo {
private int $id;
private string $name; }
Summary
With the introduction of typed properties, it will make it easy to define the classes with more clarity. It won't leave any confusion while assigning the values to the typed properties. In the older version of PHP, the developers were forced to use getter and setter methods to enforce type contracts. Also, there is no need to add comments for type hinting.