Properties and methods represent the state and behavior that define a class.
But we don’t want any part of the code to be able to modify critical variables without control. That’s why there are Visibility Modifiers.
The Three Levels of Access
In PHP (and in most OOP languages), we have three keywords to define who can see and touch a property or a method:
Total access. It can be read and modified from anywhere: from inside the class and from outside.
- Use: Methods you want the user to use (
fly(),turnOn()) or trivial data.
Exclusive access. Only the class itself can see this property. It’s invisible from the outside.
- Use: Critical internal state (battery, passwords, internal logic). If you try to access it from outside, PHP will throw a Fatal Error.
Family access. It’s like private, but with one exception: classes that inherit from this one (children) can also access it.
- Use: We’ll see this in depth in the “Inheritance” lesson. For now, just remember it’s a “private shared with the family”.
Applying Security to Our Drone
Let’s fix the mess from the previous lesson. Let’s make the battery private so no one can set absurd values.
class Drone {
// PUBLIC: Anyone can see the model
public string $model;
// PRIVATE: Only the Drone can touch the battery
private int $battery = 100;
// Method to READ the battery safely (Getter)
public function getBattery(): int {
return $this->battery;
}
// Method to FLY (Modifies the battery internally)
public function fly(): void {
if ($this->battery >= 10) {
$this->battery -= 10; // HERE we can touch it (we are inside)
echo "Flying... Remaining battery: {$this->battery}%\n";
} else {
echo "Low battery. Landing.\n";
}
}
}Let’s test the secured code:
$myDrone = new Drone();
$myDrone->model = "SkyHunter X";
// Trying to hack the battery from outside
// $myDrone->battery = 5000;
// ❌ FATAL ERROR: Cannot access private property Drone::$battery
// Correct way: Use the public methods
$myDrone->fly(); // ✅ Works, goes down to 90%
echo $myDrone->getBattery(); // ✅ Reads the value (90)This way, we have forced the only way to drain the battery is by flying and we protect the integrity of the data.
readonly Properties (PHP 8.1+)
Sometimes you have data that shouldn’t be private (you want it to be visible), but it should never change once created. For example: a Drone’s serial number or a user’s ID.
Before PHP 8.1, you had to make them private and create a get... method just to read them. It was a lot of boring code.
Now we have readonly.
readonly Rules:
- It can only be written once (usually in the constructor).
- After that, the property cannot be reassigned. If it contains an object, the internal state of that object could change.
- It cannot have a default value in its definition.
class Drone {
// Can be read from outside, but NEVER modified
public readonly string $serialNumber;
public function __construct(string $serial) {
$this->serialNumber = $serial; // First and only assignment
}
}
$drone = new Drone("SN-12345");
echo $drone->serialNumber; // ✅ "SN-12345"
// Trying to change it later
// $drone->serialNumber = "SN-99999";
// ❌ FATAL ERROR: Cannot modify readonly propertyIt’s perfect for Data Transfer Objects (DTOs), a pattern you’ll use extensively to move data safely between layers of your application.
Property Typing
Since PHP 7.4, you must always specify the type for properties.
- Bad (2010 Style):
class User {
public $name; // What is this? A string? An array?
}- Good (with a typed property):
class User {
public string $name;
public ?int $age; // Can be int or null
}If you try to put an array into $name, PHP will alert you immediately. Robust code starts by properly defining the data we handle.