Question
In PHP classes, what is the difference between public, private, and protected methods and properties? When should each one be used, and why?
Examples:
// Public
public $variable;
public function doSomething() {
// ...
}
// Private
private $variable;
private function doSomething() {
// ...
}
// Protected
protected $variable;
protected function doSomething() {
// ...
}
Short Answer
By the end of this page, you will understand how visibility works in PHP classes, what public, private, and protected mean, and how to choose the right one for properties and methods. You will also see practical examples, common mistakes, and how these access levels are used in real projects.
Concept
In PHP, public, private, and protected are visibility keywords. They control where a property or method can be accessed from.
Visibility matters because classes are meant to hide internal details and expose only the parts that other code should use. This helps you:
- protect important data from accidental changes
- keep class internals flexible
- make your code easier to understand and maintain
- enforce clear boundaries between a class and the outside world
Here is the core idea:
public: accessible from anywhereprivate: accessible only inside the same classprotected: accessible inside the same class and its child classes
Why this matters
Imagine a class represents a bank account. You probably want other code to call a method like deposit() or withdraw(), but you do not want external code directly changing the balance in unsafe ways.
That is why visibility is useful: it lets you define a safe public interface and hide the internal implementation.
Quick definition
public
Use public for methods and properties that are intended to be used by other parts of your program.
class User {
public string $name = "Alice";
public function greet(): string {
return "Hello, " . $this->name;
}
}
$user = new User();
echo $user->name; // allowed
echo $user->greet(); // allowed
private
Use private for internal details that should only be used inside that exact class.
class User {
private string $password = "secret";
private function hashPassword(): string {
return sha1($this->password);
}
public function getPasswordHash(): string {
return $this->hashPassword();
}
}
Outside code cannot access $password or hashPassword() directly.
protected
Use protected when something should stay hidden from outside code but still be available to child classes.
class Animal {
protected string $type = "animal";
protected function getType(): string {
return $this->type;
}
}
class Dog extends Animal {
public function describe(): string {
return "This is a " . $this->getType();
}
}
A Dog object can use inherited protected members, but outside code cannot.
The rule in one table
| Visibility | Same class | Child class | Outside class |
|---|---|---|---|
public | Yes | Yes | Yes |
protected | Yes | Yes | No |
private | Yes | No | No |
General guideline
A common rule is:
- make things
privateby default - use
protectedonly when inheritance truly needs it - use
publicfor the class API you want others to rely on
This keeps your classes safer and easier to change later.
Mental Model
Think of a class like a building.
publicis the front door: anyone is allowed in.protectedis the staff-only area: the building's workers and approved branches can enter.privateis the owner's locked office: only that exact office owner can access it.
Another way to think about it:
public= what the class promises to the outside worldprivate= how the class works internallyprotected= internal tools that subclasses are allowed to reuse
This mental model helps with design:
- If outside code should use it directly, make it
public. - If it is an implementation detail, make it
private. - If subclasses need it but outside code should not, make it
protected.
Syntax and Examples
Basic syntax
class Example {
public string $publicProperty = 'visible everywhere';
protected string $protectedProperty = 'visible in class and subclasses';
private string $privateProperty = 'visible only in this class';
public function publicMethod(): void {
echo "Public method\n";
}
protected function protectedMethod(): void {
echo "Protected method\n";
}
private function privateMethod(): void {
echo "Private method\n";
}
}
Example: safe class design
class BankAccount {
private float $balance = 0;
public function deposit(float $amount): void {
if ($amount > 0) {
$this->balance += $amount;
}
}
public function getBalance(): float {
return $this->balance;
}
}
$account = new BankAccount();
$account->deposit(100);
echo $account->getBalance(); // 100
Why this is good
$balanceisprivate, so outside code cannot set it to an invalid value.deposit()ispublic, because it is part of the class interface.getBalance()ispublic, because callers need to read the value safely.
Example: protected with inheritance
class Vehicle {
protected string $brand;
public function __construct(string $brand) {
$this->brand = $brand;
}
}
class Car extends Vehicle {
public function getDescription(): string {
return "Car brand: " . $this->brand;
}
}
$car = new Car("Toyota");
echo $car->getDescription();
Why protected works here
Vehiclewants child classes likeCarto use$brand.- But outside code should not directly modify
$brand.
Example: private does not pass to child classes
class ParentClass {
private string $secret = 'hidden';
}
class ChildClass extends ParentClass {
public function reveal(): string {
return $this->secret; // error
}
}
This fails because private members belong only to ParentClass, not to ChildClass.
Step by Step Execution
Consider this example:
class Counter {
private int $count = 0;
public function increment(): void {
$this->count++;
}
public function getCount(): int {
return $this->count;
}
}
$counter = new Counter();
$counter->increment();
$counter->increment();
echo $counter->getCount();
Step by step
1. The class is defined
Counter has:
- a private property
$count - a public method
increment() - a public method
getCount()
2. An object is created
$counter = new Counter();
At this point:
$counteris an instance ofCounter- its internal
$countstarts at0
3. increment() is called the first time
$counter->increment();
Inside the class:
$this->count++;
Now $count becomes 1.
4. increment() is called again
$counter->increment();
Now $count becomes 2.
5. getCount() is called
echo $counter->getCount();
The method returns the private property value, which is 2.
Important observation
This would not be allowed:
$counter->count = 100;
Why? Because $count is private. Only methods inside Counter can access it directly.
That is the main purpose of visibility: control access to class internals.
Real World Use Cases
1. Protecting data in domain objects
In an e-commerce app, an Order class may store internal state such as total price, status, or discount calculations.
class Order {
private float $total = 0;
public function addItem(float $price): void {
$this->total += $price;
}
public function getTotal(): float {
return $this->total;
}
}
This prevents outside code from doing something unsafe like:
// Not allowed if $total is private
$order->total = -500;
2. Creating a clean public API
Libraries often expose only a few public methods and keep helper logic private.
class EmailSender {
public function send(string $to, string $message): void {
$formatted = $this->formatMessage($message);
// send email
}
private function formatMessage(string $message): string {
return trim($message);
}
}
Users of the class only need send(), not formatMessage().
3. Sharing behavior with subclasses
Framework base classes often use protected methods or properties so child classes can customize behavior.
class BaseController {
protected function json(array $data): string {
return json_encode($data);
}
}
class UserController extends BaseController {
public function index(): string {
return $this->json(['users' => []]);
}
}
4. Enforcing business rules
A UserAccount may need to validate state changes through public methods rather than direct property access.
class UserAccount {
private bool $active = false;
public function activate(): void {
$this->active = true;
}
public function isActive(): bool {
return $this->active;
}
}
This keeps business logic in one place.
Real Codebase Usage
In real projects, visibility is used to separate a class into two parts:
- public API: what other code is allowed to call
- internal implementation: helper methods and internal state
Common patterns
Guarding internal state
Developers often make properties private and expose public getter/setter methods only when needed.
class Product {
private float $price;
public function setPrice(float $price): void {
if ($price < 0) {
throw new InvalidArgumentException('Price cannot be negative');
}
$this->price = $price;
}
public function getPrice(): float {
return $this->price;
}
}
This allows validation before changing the value.
Helper methods stay private
If a method is only used inside the class, it is usually private.
class ReportService {
public function generate(): string {
$data = $this->loadData();
return $this->format($data);
}
private function loadData(): array {
return ['sales' => 100];
}
private function format(array $data): string {
return json_encode($data);
}
}
Protected extension points
Frameworks and reusable base classes sometimes use protected to let subclasses customize behavior.
class BaseLogger {
public function log(string $message): void {
echo $this->prefix() . $message;
}
protected function prefix(): string {
return '[LOG] ';
}
}
class ErrorLogger extends BaseLogger {
protected function prefix(): string {
return '[ERROR] ';
}
}
Prefer narrow access
A good design habit is to choose the most restrictive visibility that still works:
- start with
private - change to
protectedonly if a subclass really needs access - use
publiconly for the intended external interface
This reduces coupling and makes refactoring easier.
Common Mistakes
1. Making everything public
Beginners often mark all properties and methods as public.
class User {
public string $email;
public string $password;
}
Why this is a problem
- outside code can change anything at any time
- validation becomes harder
- internal structure becomes part of the public contract
Better approach
class User {
private string $email;
private string $password;
public function setEmail(string $email): void {
$this->email = $email;
}
public function getEmail(): string {
return $this->email;
}
}
2. Expecting child classes to access private members
Broken example:
class ParentClass {
private string $name = 'Parent';
}
class ChildClass extends ParentClass {
public function getName(): string {
return $this->name; // error
}
}
Fix
If the child must access it, use protected or provide a public/protected method.
class ParentClass {
protected string $name = 'Parent';
}
3. Using protected when private is enough
protected is sometimes overused.
If a property or method does not need to be accessed by subclasses, private is safer.
4. Accessing private/protected members from outside the class
Broken example:
class Test {
private string $secret = 'abc';
}
$test = new Test();
echo $test->secret; // error
Fix
Expose controlled access through a public method.
class Test {
private string $secret = 'abc';
public function getSecret(): string {
return $this->secret;
}
}
5. Treating getters and setters as automatically required
Not every property needs a getter or setter. Sometimes a property should stay completely internal.
Use public methods only when they support real class behavior or needed access.
6. Exposing implementation details too early
If helper methods are public, other code may start relying on them. Later, changing them becomes risky.
Keep helper methods private unless they are meant to be part of the class interface.
Comparisons
Visibility comparison
| Keyword | Accessible inside same class | Accessible in child classes | Accessible from outside | Typical use |
|---|---|---|---|---|
public | Yes | Yes | Yes | Class API |
protected | Yes | Yes | No | Shared internals for inheritance |
private | Yes | No | No | Internal implementation details |
private vs protected
| Choice | Use when |
|---|---|
private | Only the current class should access it |
protected | Subclasses also need access |
public vs getter/setter methods
| Approach | Pros | Cons |
|---|---|---|
| Public property | Simple to read/write | No control over changes |
| Private property + public methods | Validation and flexibility | Slightly more code |
Which one should you choose?
- Choose
publicfor methods that define what the class does. - Choose
privatefor internal state and helper logic. - Choose
protectedonly when designing for inheritance.
A useful default is:
- Start with
private - Move to
protectedonly if a child class genuinely needs access - Use
publicfor the external contract
Cheat Sheet
Quick rules
public= accessible everywhereprotected= accessible in the class and subclassesprivate= accessible only in the same class
Access table
| From where? | public | protected | private |
|---|---|---|---|
| Same class | Yes | Yes | Yes |
| Child class | Yes | Yes | No |
| Outside object usage | Yes | No | No |
Syntax
class Example {
public $a;
protected $b;
private $c;
public function one() {}
protected function two() {}
private function three() {}
}
Best practice
- Prefer
privateby default - Use
publicfor the intended API - Use
protectedfor inheritance-based extension - Keep internal helpers non-public
Common edge case
private members are not inherited in an accessible way by child classes.
class A {
private $x = 1;
}
class B extends A {
public function test() {
return $this->x; // not allowed
}
}
Good design pattern
class Account {
private float $balance = 0;
public function deposit(float $amount): void {
if ($amount > 0) {
$this->balance += $amount;
}
}
public function getBalance(): float {
return $this->balance;
}
}
FAQ
What does public mean in PHP?
public means a property or method can be accessed from anywhere: inside the class, from child classes, and from outside objects.
What does private mean in PHP?
private means only the same class can access that property or method directly.
What does protected mean in PHP?
protected means the current class and its child classes can access it, but outside code cannot.
Should class properties be private in PHP?
Usually, yes. Making properties private helps protect data and lets you control access through methods.
Can a child class access private properties in PHP?
No. A child class cannot directly access a parent's private properties or methods.
When should I use protected instead of private?
Use protected when subclasses genuinely need access to a property or method. Otherwise, prefer private.
Is it bad to make everything public?
In most cases, yes. It exposes internal details, makes validation harder, and increases coupling between parts of your code.
Can protected members be accessed outside the class?
No. protected members are not accessible through an object from outside the class hierarchy.
Mini Project
Description
Build a simple BankAccount class to practice choosing the right visibility for properties and methods. This project demonstrates how to protect internal data, expose safe public methods, and optionally use a protected helper for subclasses.
Goal
Create a PHP class that allows deposits and withdrawals through public methods while keeping the balance protected from direct external modification.
Requirements
- Create a
BankAccountclass with a balance that cannot be accessed directly from outside the class. - Add public methods to deposit money, withdraw money, and read the current balance.
- Prevent invalid deposits or withdrawals, such as negative amounts or withdrawing more than the balance.
- Add one internal helper method for validation.
- Show the class being used with a few example operations.
Keep learning
Related questions
Are PDO Prepared Statements Enough to Prevent SQL Injection in PHP?
Learn how PDO prepared statements prevent SQL injection in PHP, what they protect, and the mistakes that still leave MySQL apps vulnerable.
Can You Bind an Array to an IN Clause in PHP PDO?
Learn how PDO handles placeholders in IN() clauses, why arrays cannot be bound directly, and the safe PHP pattern to build dynamic queries.
Choosing the Right MySQL Collation for PHP and UTF-8
Learn how MySQL character sets and collations work with PHP, and how to choose a practical UTF-8 setup for web applications.