The constructor and promotion
In the previous lesson every new object got its starting values from the class: the counter always started at 0. But much cannot be known in advance. Every user has their own name, and it has to be set at the moment the object appears.
Let's go back to the houses. The builders don't start empty-handed: they get the order right away—how many floors and what color the walls are. From that order the house is built the way it should be from the start.
The __construct method
In PHP the constructor takes that order. A constructor is a method named __construct that PHP calls by itself when new builds an object. The arguments of new User('Anna') go into its parameters:
<?php
class User
{
public string $name;
public function __construct(string $name)
{
$this->name = $name;
}
}
$anna = new User('Anna');
echo $anna->name, "\n"; // AnnaLet's go through it step by step:
public string $name;declares a property with no starting value: the name will come from outside.new User('Anna')builds an object and at once calls its__constructwith the string'Anna'.- Inside the constructor
$thisis the new object, and$this->name = $name;writes the name into its property. - The finished object goes into
$anna, andechoprintsAnna.
Two underscores at the start of a name mark the methods PHP calls by itself. You don't write $anna->__construct('Anna'): the constructor runs once, on every new.
Property promotion
Look at how many times the name appears in the class User: in the property declaration, in the parameter and in the assignment. Every new property would take three lines. Since PHP 8.0 one notation does all of it:
<?php
class User
{
public function __construct(
public string $name,
public int $level = 1,
) {}
}
$anna = new User('Anna');
$boris = new User('Boris', 3);
echo $anna->name, ' ', $anna->level, "\n"; // Anna 1
echo $boris->name, ' ', $boris->level, "\n"; // Boris 3Property promotion is the notation in which the word public before a constructor parameter declares a property and assigns the argument to it. Let's take it apart:
public string $namecreates the property$nameand puts the first argument ofnewinto it.public int $level = 1works the same way, but the parameter has a default value:new User('Anna')gets level1.- The constructor body is empty,
{}: promotion did all the work. If there is a body, it runs after the properties are written. - Each object has its own values, so the program prints
Anna 1andBoris 3.
Instead of public you can write private or protected: then the property is closed to code outside the class. These three words are called visibility modifiers. The type can also be a class name: the parameter private Logger $log declares a property that holds an object of the class Logger.
Interviewers ask what property promotion does. The answer:
- a modifier on a constructor parameter declares the property and assigns the argument to it in one step;
- the line
$this->name = $name;is no longer needed; - the result is an ordinary property, separate in each object, with a type and a default value if you give them.
Common mistake
A property was declared without a starting value and never set in the constructor:
<?php
class Order
{
public int $total;
}
$order = new Order();
echo $order->total, "\n"; // ✗Fatal error: Uncaught Error: Typed property Order::$total must not be accessed before initializationThis is an error, not a warning: the program stops at that line. A typed property that was given no value is in a special "not set" state, and that is not null. Here the house picture breaks down: you can at least look around an unfinished house, but PHP won't let you read a property that was never set.
The fix is to give the property a starting value, public int $total = 0;, or to write it in the constructor.
Key points
- The constructor
__constructruns by itself on everynewand gets the arguments ofnew User('Anna'). - Property promotion:
public string $nameamong the constructor parameters declares a property and assigns the argument to it. - A promoted parameter may have a default value:
public int $level = 1. - A typed property with no value cannot be read: that is an
Error, notnull.