Defining a Class
<?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
$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
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
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
| Modifier | Accessible from |
|---|---|
public | Anywhere |
protected | Same class + subclasses |
private | Same class only |
<?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();
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
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 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
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
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
// 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)