Encapsulation
Encapsulation is one of the Four Pillars of OOP.
The four pillars are:
- Encapsulation
- Inheritance
- Polymorphism
- Abstraction
Encapsulation is probably one of the most important concepts because it protects object data and prevents invalid states.
What is Encapsulation?
Encapsulation means:
Bundling data and methods together while hiding internal implementation details.
Or simply:
Protect object data from direct modification.
Real Life Example
Think of a car.
You accelerate using:
Pedal
You do NOT directly modify:
Engine RPM
Fuel Injection
Air Intake
Those internal details are hidden.
This is encapsulation.
Bank Example
Imagine if everyone could directly modify bank balances.
Bad:
$account->balance =
1000000000;
Anyone could become rich instantly.
Encapsulation prevents this.
Without Encapsulation
class Player {
public int $money = 0;
}
Usage:
$player->money =
-500000;
Invalid state.
Another example:
$player->money =
999999999999999999;
Game economy breaks.
Why Encapsulation Exists
To protect:
✅ Data Integrity
✅ Validation Rules
✅ Security
✅ Maintainability
Proper Encapsulation
class Player {
private int $money = 0;
}
Now:
$player->money
produces an error.
Visualization
Outside World
↓
Public Methods
↓
Private Data
Getters and Setters
Encapsulation is usually implemented using:
- Getters
- Setters
Getter
Returns data.
public function getMoney()
: int {
return $this->money;
}
Usage:
echo
$player->getMoney();
Setter
Modifies data.
public function setMoney(
int $money
): void {
$this->money =
$money;
}
Usage:
$player->setMoney(
5000
);
Why Setters are Useful
Because validation can be added.
Example:
public function setMoney(
int $money
): void {
if (
$money < 0
) {
return;
}
$this->money =
$money;
}
Negative values are prevented.
Validation Example
class Player {
private int $health = 20;
public function setHealth(
int $health
): void {
if (
$health < 0
) {
$health = 0;
}
if (
$health > 20
) {
$health = 20;
}
$this->health =
$health;
}
}
Benefits of Encapsulation
1. Data Protection
Nobody can directly modify internals.
2. Validation
Ensure valid data.
3. Easier Maintenance
Internal implementation can change.
External code remains unchanged.
4. Security
Sensitive information stays hidden.
Example
Bad:
public string $password;
Good:
private string $password;
Real World Example
User class:
class User {
private string $password;
}
Methods:
setPassword()
verifyPassword()
Nobody should access raw password.
Example
class User {
private string $password;
public function setPassword(
string $password
): void {
$this->password =
password_hash(
$password,
PASSWORD_DEFAULT
);
}
}
This is encapsulation.
Data Hiding
Encapsulation is sometimes called:
Data Hiding
because internal state becomes hidden.
Visualization
Player
│
├── private money
├── private health
│
├── public getMoney()
├── public addMoney()
└── public damage()
Read-Only Data
Sometimes we only want reading.
Example:
private string $uuid;
Getter:
public function getUuid()
: string {
return $this->uuid;
}
No setter.
Now UUID cannot change.
Immutable Objects
Another approach:
readonly
Example:
public readonly string $uuid;
Encapsulation Example
class BankAccount {
private float $balance = 0;
public function deposit(
float $amount
): void {
if (
$amount <= 0
) {
return;
}
$this->balance +=
$amount;
}
public function withdraw(
float $amount
): void {
if (
$amount >
$this->balance
) {
return;
}
$this->balance -=
$amount;
}
public function getBalance()
: float {
return $this->balance;
}
}
PocketMine Example
Simplified Player:
class Player {
private int $health = 20;
public function getHealth()
: int {
return $this->health;
}
public function setHealth(
int $health
): void {
if (
$health < 0
) {
$health = 0;
}
$this->health =
$health;
}
}
Why Not Public?
Bad:
$player->health =
-9999;
Could crash plugins.
Encapsulation in APIs
API Response:
$user->getName();
You don't know where name comes from:
- Database
- Cache
- File
- Redis
Implementation remains hidden.
Internal Implementation Can Change
Today:
return $this->money;
Tomorrow:
return
$this->wallet
->getBalance();
Outside code remains same.
This is extremely powerful.
Encapsulation and Dependency Injection
private Database $database;
Expose only required methods.
Never expose database connection publicly.
Enterprise Example
UserService
↓
Repository
↓
Database
Everything remains encapsulated.
Real PocketMine Architecture
Player
│
├── private NetworkSession
├── private Inventory
├── private Effects
├── private Metadata
│
├── public sendMessage()
├── public teleport()
└── public kick()
Internals remain hidden.
Common Beginner Mistakes
Making Everything Public
Bad:
public int $money;
Creating Useless Getters
Bad:
getMoney()
setMoney()
without validation.
Exposing Sensitive Data
Bad:
public string $password;
Returning Mutable Objects
Example:
return $this->inventory;
External code may modify it unexpectedly.
Best Practices
✅ Keep properties private.
✅ Expose only required methods.
✅ Validate all data.
✅ Hide implementation details.
✅ Protect sensitive information.
Rule of Thumb
Private by Default
Only expose what is necessary.
Exercises
Exercise 1
Create:
class Player {
private int $money = 0;
}
Add:
addMoney()
removeMoney()
getMoney()
Exercise 2
Create:
BankAccount
Prevent negative balances.
Exercise 3
Create password setter using:
password_hash()
Mini Project
Create:
PlayerProfile
Properties:
uuid
name
rank
coins
kills
deaths
Use proper encapsulation.
Quiz
What is Encapsulation?
Answer
Hiding internal implementation and protecting object data.
Which visibility is commonly used?
Answer
private
Why are setters useful?
Answer
They allow validation.
Why should passwords never be public?
Answer
Sensitive information must remain hidden.
Summary
Encapsulation provides:
✅ Security
✅ Validation
✅ Maintainability
✅ Better Architecture
✅ Data Integrity
References
https://www.php.net/manual/en/language.oop5.visibility.php
https://www.php.net/manual/en/language.oop5.properties.php
Next Chapter
➡ Inheritance
➡ Polymorphism
➡ Abstraction