Reader Stacks

What Are Access Modifiers in Object-Oriented Programming?

public, protected, and private control which code is allowed to touch a class's properties and methods — the same three-level model works nearly identically across PHP, Java, and most other OOP languages.

Access modifiers control which code is allowed to read or call a class's properties and methods — the three-level model (public, protected, private) is essentially identical across PHP, Java, and most other mainstream object-oriented languages, even though the exact keyword syntax differs slightly.

public

class User
{
    public string $name;

    public function greet(): string
    {
        return "Hello, {$this->name}";
    }
}

$user = new User();
$user->name = 'Alex'; // accessible from anywhere
$user->greet();

public members are accessible from anywhere — inside the class, from a subclass, and from outside code that holds an instance of the object.

protected

class Animal
{
    protected string $sound = 'generic noise';

    protected function makeSound(): string
    {
        return $this->sound;
    }
}

class Dog extends Animal
{
    protected string $sound = 'Woof';

    public function bark(): string
    {
        return $this->makeSound(); // accessible: Dog extends Animal
    }
}

$dog = new Dog();
$dog->bark();       // fine — bark() is public
// $dog->makeSound(); // error — makeSound() is protected, not accessible from outside

protected members are accessible within the defining class and any subclass, but not from outside code holding an instance directly — this is the level specifically meant for internal implementation details a subclass is expected to build on.

private

class BankAccount
{
    private float $balance = 0;

    public function deposit(float $amount): void
    {
        $this->balance += $amount;
    }

    public function getBalance(): float
    {
        return $this->balance;
    }
}

$account = new BankAccount();
$account->deposit(100);
// $account->balance; // error — private, not accessible at all outside the class
echo $account->getBalance(); // the only sanctioned way to read it

private members are accessible only within the exact class that defines them — not even a subclass can access a parent's private property directly, which is the key distinction from protected.

Why this matters: encapsulation

Restricting direct access to a class's internal state (like BankAccount::$balance above) and exposing only controlled methods to modify it (deposit(), rather than letting outside code set $balance directly) is what encapsulation actually means in practice — it prevents external code from putting an object into an invalid state that the class's own logic wasn't designed to handle.

The same concept in Java

public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Java's syntax and the getter/setter convention shown here are more rigidly enforced by convention than PHP's, but the underlying three-level access model (public/protected/private) is the same concept, just expressed with the same keywords in a different language.

Choosing the right modifier when designing a class

A reasonable default is starting with private and only widening to protected or public when a specific, deliberate reason exists to expose something — this default-to-restrictive approach keeps a class's public surface area intentional rather than accidentally exposing internal details that later become difficult to change without breaking other code that came to depend on them.