PHP Access Modifiers
Introduction
Access modifiers are a fundamental concept in Object-Oriented Programming (OOP) that control the visibility and accessibility of properties and methods within your PHP classes. They are essential for implementing encapsulation - one of the four pillars of OOP - which is the practice of hiding the internal state and functionality of an object and only allowing access through a public API.
In PHP, there are three main access modifiers:
- public - accessible from anywhere
- protected - accessible within the class and its child classes
- private - accessible only within the class itself
Understanding access modifiers helps you design more secure and maintainable code by restricting how your class members can be accessed and modified.
Basic Syntax
Access modifiers are specified before the property or method declaration:
class MyClass {
public $publicProperty; // Accessible from anywhere
protected $protectedProperty; // Accessible within this class and child classes
private $privateProperty; // Accessible only within this class
public function publicMethod() {
// Accessible from anywhere
}
protected function protectedMethod() {
// Accessible within this class and child classes
}
private function privateMethod() {
// Accessible only within this class
}
}
Public Access Modifier
The public
access modifier makes properties and methods accessible from anywhere - inside the class, in child classes, and outside the class.
Example
<?php
class User {
public $username;
public function displayUsername() {
return "Username: " . $this->username;
}
}
// Create a new user
$user = new User();
// Access public property directly
$user->username = "john_doe";
// Call public method
echo $user->displayUsername();
?>
Output:
Username: john_doe
In this example, both the $username
property and the displayUsername()
method are public, making them accessible from outside the class.
Protected Access Modifier
The protected
access modifier makes properties and methods accessible only within the class itself and any child classes (subclasses) that extend it.
Example
<?php
class User {
protected $id;
public function __construct($id) {
$this->id = $id;
}
protected function generateSecretCode() {
return hash('sha256', $this->id . time());
}
public function getAccessToken() {
return $this->generateSecretCode();
}
}
class Admin extends User {
public function displayAdminSecret() {
// Can access protected property from parent class
return "Admin ID: " . $this->id . ", Secret: " . $this->generateSecretCode();
}
}
// Create a new user
$user = new User(1001);
// This would cause an error - protected property
// echo $user->id;
// This would cause an error - protected method
// echo $user->generateSecretCode();
// This works - public method that uses protected method internally
echo "User token: " . $user->getAccessToken() . "
";
// Create an admin
$admin = new Admin(5001);
echo $admin->displayAdminSecret();
?>
Output:
User token: 3a5d8f24c8bf8976f3db309a5d9cc6f7e42d0d8a4c7982e3f9f5e0a15eb88f1a
Admin ID: 5001, Secret: 7b1e9a3f8c2d6e5b4a7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9
In this example:
- The
$id
property andgenerateSecretCode()
method are protected - They cannot be accessed directly from outside the class
- But they can be accessed within the class and in the child
Admin
class
Private Access Modifier
The private
access modifier makes properties and methods accessible only within the class in which they are defined. They cannot be accessed from child classes or from outside the class.
Example
<?php
class BankAccount {
private $balance;
private $accountNumber;
public function __construct($accountNumber, $initialBalance) {
$this->accountNumber = $accountNumber;
$this->balance = $initialBalance;
}
private function validateTransaction($amount) {
return $amount > 0 && $amount <= $this->balance;
}
public function withdraw($amount) {
if ($this->validateTransaction($amount)) {
$this->balance -= $amount;
return "Withdrew $" . $amount . ". New balance: $" . $this->balance;
}
return "Transaction failed: Insufficient funds or invalid amount";
}
public function getBalance() {
return "Account #" . substr($this->accountNumber, -4) . ": $" . $this->balance;
}
}
class SavingsAccount extends BankAccount {
public function applyInterest($rate) {
// This would cause an error - cannot access private property from parent
// $this->balance += $this->balance * $rate;
// Instead, we need to use public methods
$currentBalance = parent::getBalance();
return "Cannot directly modify balance. Current " . $currentBalance;
}
}
// Create a bank account
$account = new BankAccount("1234567890", 1000);
// This would cause an error - private property
// echo $account->balance;
// This would cause an error - private method
// $account->validateTransaction(50);
// These work - public methods
echo $account->getBalance() . "
";
echo $account->withdraw(250) . "
";
// Create a savings account
$savings = new SavingsAccount("0987654321", 5000);
echo $savings->applyInterest(0.05);
?>
Output:
Account #7890: $1000
Withdrew $250. New balance: $750
Cannot directly modify balance. Current Account #4321: $5000
In this example:
- The
$balance
and$accountNumber
properties are private - The
validateTransaction()
method is private - None of these can be accessed from outside the class or from child classes
- Even the
SavingsAccount
class cannot directly access the$balance
property of its parent
Visual Comparison of Access Modifiers
Here's a diagram showing the visibility scope of each access modifier:
No Modifier (Default)
If you don't specify an access modifier, PHP will treat the property or method as public
by default. However, it's considered good practice to always explicitly declare access modifiers for clarity.
<?php
class MyClass {
$property; // Implicitly public (not recommended)
function method() {
// Implicitly public (not recommended)
}
}
?>
Practical Applications
User Profile System
Here's a real-world example of how you might use access modifiers in a user profile system:
<?php
class UserProfile {
private $userId;
private $email;
protected $lastLogin;
public $displayName;
public function __construct($userId, $email, $displayName) {
$this->userId = $userId;
$this->email = $email;
$this->displayName = $displayName;
$this->lastLogin = date('Y-m-d H:i:s');
}
private function validateEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL);
}
public function updateEmail($newEmail) {
if ($this->validateEmail($newEmail)) {
$this->email = $newEmail;
return true;
}
return false;
}
public function getEmail() {
// Return partially hidden email for security
$parts = explode('@', $this->email);
$name = substr($parts[0], 0, 2) . str_repeat('*', strlen($parts[0]) - 2);
return $name . '@' . $parts[1];
}
protected function updateLastLogin() {
$this->lastLogin = date('Y-m-d H:i:s');
}
public function getLastLoginInfo() {
return "Last login: " . $this->lastLogin;
}
}
class AdminProfile extends UserProfile {
public function forceUpdateLogin() {
// Can access protected method
$this->updateLastLogin();
return "Admin updated login time to: " . $this->lastLogin;
}
// Can't access private properties/methods of parent
// public function getFullEmail() {
// return $this->email; // This would cause an error
// }
}
// Create a user profile
$user = new UserProfile(1, "[email protected]", "John");
// Access public property
echo "Display name: " . $user->displayName . "
";
// Use public methods to interact with private property
echo "Email: " . $user->getEmail() . "
";
$user->updateEmail("[email protected]");
echo "Updated email: " . $user->getEmail() . "
";
// Get info derived from protected property
echo $user->getLastLoginInfo() . "
";
// Create an admin profile
$admin = new AdminProfile(2, "[email protected]", "Admin");
echo $admin->forceUpdateLogin();
?>
Output:
Display name: John
Email: jo**@example.com
Updated email: jo**@example.com
Last login: 2023-05-20 14:30:45
Admin updated login time to: 2023-05-20 14:30:45
In this example:
- Private properties (
$userId
,$email
) and methods (validateEmail()
) are only accessible within theUserProfile
class - Protected property (
$lastLogin
) and method (updateLastLogin()
) are accessible in bothUserProfile
andAdminProfile
classes - Public property (
$displayName
) and methods are accessible everywhere
Benefits of Using Access Modifiers
- Encapsulation: Hide implementation details and expose only what's necessary
- Data Protection: Prevent accidental modification of critical data
- Maintainability: Change internal implementation without affecting external code
- Controlled Access: Provide specific interfaces for interacting with your objects
- Flexibility: Allow child classes to extend functionality without exposing all details
Common Practices and Patterns
-
Make properties private or protected: Always restrict direct access to properties and provide public getter and setter methods when needed.
-
Use the principle of least privilege: Start with the most restrictive access modifier (
private
) and only widen access when necessary. -
"Getter" and "Setter" pattern: Use public methods to access and modify private properties.
phpprivate $name;
public function getName() {
return $this->name;
}
public function setName($name) {
// Validate before setting
$this->name = trim($name);
} -
Protected for inheritance: Use protected when you want child classes to have access.
Summary
Access modifiers in PHP OOP are powerful tools for implementing encapsulation and controlling the visibility of your class members:
- public: Accessible from anywhere
- protected: Accessible within the class and its children
- private: Accessible only within the defining class
By properly using access modifiers, you can create more robust, maintainable, and secure code. They help you hide implementation details, protect sensitive data, and provide a clean interface for working with your objects.
Exercises
-
Create a
Product
class with private properties forprice
andstockLevel
, and public methods to check availability and display formatted price. -
Extend the
BankAccount
example by creating aCheckingAccount
class that extends it and implements atransferTo
method. -
Modify the
UserProfile
class to include additional private properties likepasswordHash
andsecurityQuestion
, with appropriate public methods to update them securely.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)