Constructors & Destructors
Learn how PHP's __construct() and __destruct() magic methods let you initialize and clean up objects automatically.
Introduction
Every time you create an object with the `new` keyword, PHP gives you a chance to run setup code automatically. That setup code lives in a special method called a constructor. Without it, you would have to manually call a separate method every time you created an object just to set its initial values — easy to forget, and easy to get wrong.
PHP also provides the opposite hook: a destructor, which runs automatically when an object is about to be destroyed. This lesson covers both, along with a modern PHP 8 shortcut that removes a lot of repetitive constructor code.
- How __construct() runs automatically when an object is created.
- How to use a constructor to set initial property values.
- How to give constructor parameters default values.
- How __destruct() runs when an object is destroyed or the script ends.
- How PHP 8 constructor property promotion shortens your classes.
What Is a Constructor?
A constructor is a method named `__construct()` (with two leading underscores). PHP calls this method automatically the moment you write `new ClassName(...)` — you never call `__construct()` yourself. Its job is to prepare the object for use, usually by assigning values to properties.
<?php
class Product
{
public string $name;
public float $price;
public function __construct(string $name, float $price)
{
$this->name = $name;
$this->price = $price;
echo "Created product: {$name}\n";
}
}
$item = new Product("Keyboard", 49.99);
echo "{$item->name} costs \${$item->price}\n";Created product: Keyboard
Keyboard costs $49.99Notice that we never called `$item->__construct(...)`. Simply writing `new Product("Keyboard", 49.99)` triggered it automatically, passing along the arguments we supplied.
Without a constructor, you would need to create an object and then set every property on separate lines, risking an object left in an incomplete or invalid state in between. A constructor guarantees the object is fully set up in one step, at the moment it is created.
Default Parameter Values
Just like regular functions, constructor parameters can have default values. This lets you create an object without supplying every argument, falling back to sensible defaults instead.
<?php
class Account
{
public string $username;
public string $role;
public bool $isActive;
public function __construct(string $username, string $role = "member", bool $isActive = true)
{
$this->username = $username;
$this->role = $role;
$this->isActive = $isActive;
}
}
$admin = new Account("sasha", "admin");
$guest = new Account("nadia");
echo "{$admin->username} is a(n) {$admin->role}\n";
echo "{$guest->username} is a(n) {$guest->role}, active: " . ($guest->isActive ? "yes" : "no") . "\n";sasha is a(n) admin
nadia is a(n) member, active: yesHere, `$admin` explicitly supplies a role, while `$guest` relies on the default value `"member"`. Default parameters keep your constructor flexible without forcing every caller to specify everything.
The __destruct() Method
The counterpart to `__construct()` is `__destruct()`. PHP calls it automatically when an object is no longer referenced anywhere, or when the script finishes running — whichever comes first. You rarely need to define one explicitly, but it is useful for cleanup work such as closing a file handle, a database connection, or a network socket.
<?php
class FileLogger
{
private $handle;
private string $path;
public function __construct(string $path)
{
$this->path = $path;
$this->handle = fopen($path, "a");
echo "Opened log file: {$path}\n";
}
public function log(string $message): void
{
fwrite($this->handle, $message . PHP_EOL);
}
public function __destruct()
{
fclose($this->handle);
echo "Closed log file: {$this->path}\n";
}
}
$logger = new FileLogger("app.log");
$logger->log("Application started");
unset($logger);
echo "After unset\n";Opened log file: app.log
Closed log file: app.log
After unsetCalling `unset($logger)` removed the only reference to the object, so PHP immediately destroyed it and ran `__destruct()` before moving on to the next line. If we never explicitly `unset()` the object, the destructor still runs automatically once the script ends.
You cannot control exactly when __destruct() runs relative to other code beyond "when the object is no longer referenced or the script ends." For anything time-critical — like committing a database transaction — call a dedicated method (e.g. close() or commit()) explicitly instead of depending on the destructor.
Constructor Property Promotion (PHP 8)
A very common pattern is a constructor that does nothing but assign each parameter to a matching property, exactly like the `Product` example earlier. PHP 8 introduced a shorthand called constructor property promotion that eliminates this repetition: adding a visibility keyword directly to a constructor parameter both declares the property and assigns it in one step.
<?php
// Traditional style
class ProductOld
{
public string $name;
public float $price;
public function __construct(string $name, float $price)
{
$this->name = $name;
$this->price = $price;
}
}
// PHP 8 constructor property promotion
class ProductNew
{
public function __construct(
public string $name,
public float $price = 0.0
) {}
}
$item = new ProductNew("Mouse", 19.99);
echo "{$item->name}: \${$item->price}\n";Mouse: $19.99Both classes behave identically, but `ProductNew` declares the properties and assigns them in a single line per parameter. This shorthand is optional — it is just a more concise way to write a very common pattern, and you will see it heavily in modern PHP codebases.
Common Mistakes
- Trying to call __construct() or __destruct() directly — PHP calls both automatically.
- Forgetting that constructor parameters without defaults must be supplied when creating the object, or PHP throws an error.
- Assuming __destruct() runs at a precise, predictable moment — use an explicit cleanup method for anything time-critical.
- Mixing promoted and non-promoted parameters carelessly, making the constructor harder to read.
Best Practices
- Use the constructor to guarantee an object always starts in a valid, fully-initialized state.
- Give parameters sensible default values when a property has an obvious "usual" value.
- Reach for constructor property promotion in PHP 8+ to keep simple classes short and readable.
- Only define __destruct() when you genuinely need cleanup logic, such as closing a resource.
Frequently Asked Questions
Can a class have more than one constructor?
No. PHP allows only one __construct() method per class. You can simulate multiple ways to create an object using default parameter values or static factory methods instead.
Is __destruct() required?
No. Most classes never define one. It is only useful when an object holds onto a resource (a file handle, socket, or connection) that needs explicit cleanup.
Does unset() always trigger __destruct() immediately?
Only if that was the last remaining reference to the object. If another variable still points to the same object, the destructor waits until all references are gone.
Can I mix promoted and regular properties?
Yes. You can promote some constructor parameters while still declaring other properties normally in the class body.
Key Takeaways
- __construct() runs automatically whenever you create an object with new.
- Constructors are the standard place to set a new object's initial property values.
- Constructor parameters can have default values, just like regular function parameters.
- __destruct() runs automatically when an object is destroyed or the script ends, and is useful for cleanup.
- PHP 8 constructor property promotion lets you declare and assign properties directly in the parameter list.
Summary
Constructors and destructors are PHP's automatic hooks into an object's birth and death. A constructor sets up initial state the moment an object is created, while a destructor handles any necessary cleanup when the object goes away. PHP 8's constructor property promotion makes the common "assign every parameter to a property" pattern much shorter to write.
- You understand how __construct() initializes new objects automatically.
- You can use default parameter values in a constructor.
- You know when and why __destruct() runs.
- You can use PHP 8 constructor property promotion to shorten your classes.