PHP Classes & Objects

Master object-oriented PHP: define classes, create objects, control visibility, write constructors, and use modern PHP 8 features like constructor promotion and readonly.

Intermediate 11 min read 12 examples

Defining a Class

PHPUser.php
<?php
declare(strict_types=1);

class User {
    // Properties (state)
    public string $name;
    public int $age;

    // Constructor - runs on new
    public function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age  = $age;
    }

    // Method (behavior)
    public function greet(): string {
        return "Hi, I am {$this->name}";
    }
}

Conventions: PascalCase for class names, one class per file, file name matches class name.

Creating Objects

PHP
<?php
$user = new User("Ruban", 30);

echo $user->name;          // Ruban
echo $user->greet();       // Hi, I am Ruban

// Each object is independent
$a = new User("Alice", 25);
$b = new User("Bob", 40);

// Type checking
var_dump($a instanceof User);   // true
echo get_class($a);             // User

Properties

Properties hold object state. PHP 7.4+ supports typed properties:

PHP
<?php
class Product {
    public string $name;
    public float  $price = 0.0;       // default value
    public ?string $sku = null;       // nullable
    public array $tags = [];
    public DateTime $createdAt;       // requires init before access
}

$p = new Product();
$p->name = "Notebook";
$p->price = 12.5;

// Accessing uninitialized typed property triggers Error
// $p->createdAt;   // ERROR if not assigned

Methods & $this

PHP
<?php
class BankAccount {
    public float $balance = 0;

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

    public function withdraw(float $amount): bool {
        if ($amount > $this->balance) return false;
        $this->balance -= $amount;
        return true;
    }

    private function log(string $msg): void {
        echo "[" . date("H:i:s") . "] $msg\n";
    }
}

$acc = new BankAccount();
$acc->deposit(100);
$acc->withdraw(30);
echo $acc->balance;     // 70

Visibility

ModifierAccessible from
publicAnywhere
protectedSame class + subclasses
privateSame class only
PHP
<?php
class Wallet {
    public string $owner;
    protected array $history = [];
    private float $balance = 0;

    public function deposit(float $n): void {
        $this->balance += $n;
        $this->history[] = ["deposit", $n];
    }

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

$w = new Wallet();
$w->owner = "Ruban";       // OK - public
// $w->balance = 5000;     // FATAL - cannot access private
echo $w->getBalance();
Default to private

Start every property as private. Expose it only when callers need to read or write it. This is encapsulation - it makes internals safe to refactor.

Constructor & Destructor

PHP
<?php
class FileLogger {
    private $handle;

    // Constructor - on new
    public function __construct(string $path) {
        $this->handle = fopen($path, "a");
    }

    public function log(string $msg): void {
        fwrite($this->handle, $msg . "\n");
    }

    // Destructor - when last reference released
    public function __destruct() {
        fclose($this->handle);
    }
}

$logger = new FileLogger("app.log");
$logger->log("Starting up");
// __destruct fires when $logger goes out of scope

Constructor Property Promotion (PHP 8.0+)

The single biggest reduction in boilerplate PHP 8 introduced:

PHP
<?php
// PHP 7 - verbose
class User {
    private string $name;
    private int $age;

    public function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age  = $age;
    }
}

// PHP 8+ - constructor promotion
class User {
    public function __construct(
        private string $name,
        private int $age = 0,
        public readonly string $id = "",
    ) {}
}

// Same usage as before
$u = new User("Ruban", 30);

Readonly Properties (PHP 8.1+)

Properties that can only be assigned once - perfect for value objects:

PHP
<?php
class Money {
    public function __construct(
        public readonly int $amount,
        public readonly string $currency,
    ) {}
}

$m = new Money(1999, "USD");
echo $m->amount;         // 1999
// $m->amount = 0;       // FATAL - readonly

// PHP 8.2+ - readonly class (all properties readonly)
readonly class Point {
    public function __construct(
        public float $x,
        public float $y,
    ) {}
}

Static Members

Static properties and methods belong to the class itself, not any instance:

PHP
<?php
class Counter {
    public static int $count = 0;

    public static function increment(): int {
        return ++self::$count;
    }
}

Counter::increment();    // 1
Counter::increment();    // 2
echo Counter::$count;    // 2

// Static factory method - very common pattern
class User {
    private function __construct(public string $name) {}

    public static function fromArray(array $data): self {
        return new self($data["name"]);
    }
}

$u = User::fromArray(["name" => "Ruban"]);

Enums (PHP 8.1+)

For fixed sets of values - much safer than string constants:

PHP
<?php
// Pure enum
enum Status {
    case Pending;
    case Active;
    case Suspended;
}

// Backed enum - each case has a scalar value
enum Role: string {
    case Admin  = "admin";
    case Editor = "editor";
    case Viewer = "viewer";

    public function label(): string {
        return match($this) {
            Role::Admin  => "Administrator",
            Role::Editor => "Content Editor",
            Role::Viewer => "Read-only Viewer",
        };
    }
}

$role = Role::Editor;
echo $role->value;       // "editor"
echo $role->label();     // "Content Editor"

// Get from value
$r = Role::from("admin");          // Role::Admin
$r = Role::tryFrom("bad");         // null (no exception)

Next Steps

Frequently Asked Questions

A class is the blueprint - the definition. An object is an instance built from that blueprint. User is the class; new User("Ruban") creates an object of that class. You can create many objects from one class.

Default to private, expose via methods only when needed. This is encapsulation - it lets you change internals later without breaking callers. Use readonly public for value objects that shouldn't change after construction.

For helpers that don't depend on instance state - factories (User::fromArray()), utility functions, or singletons. Overuse makes code hard to test and tightly coupled. Prefer instance methods when in doubt.

$this refers to the current object inside a method. It lets a method access the object's properties and call its other methods. It's automatically available - you don't pass it explicitly.

Yes for fixed sets of related values like statuses, types, or roles. Enums give you type safety - Status::Active can't be confused with a random string. PHP 8.1+ enums even support methods.