The 4 Pillars

- Encapsulation is about keeping an object's internal state private and exposing a controlled API (methods / controlled property access). In PHP you use private/protected/public, and asymmetric property visibility for read/write control.

class BankAccount
{
    private float $balance = 0.0;

    public function deposit(float $amount): void
    {
        if ($amount <= 0) {
            throw new InvalidArgumentException('Amount > 0');
        }

        $this->balance += $amount;
    }

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

$acc = new BankAccount();
$acc->deposit(100.0);

echo $acc->getBalance(); // 100

- Inheritance lets one class extend another and reuse/override behaviour. extends copies public/protected members (private members are not inherited directly). Use parent::method() to call the parent implementation.

class Vehicle
{
    public function move(): void
    {
        echo "The vehicle is moving";
    }
}

class Car extends Vehicle
{
    public function move(): void
    {
        echo "The car drives on the road";
    }
}

class Boat extends Vehicle
{
    public function move(): void
    {
        echo "The boat sails on the water";
    }
}

$vehicle = new Vehicle();
$vehicle->move();  // The vehicle is moving

$car = new Car();
$car->move();      // The car drives on the road

$boat = new Boat();
$boat->move();     // The boat sails on the water

Polymorphism describes using a common interface or base class so objects of different concrete types can be used interchangeably (Liskov Substitution Principle).

interface PaymentMethod
{
    public function pay(float $amount): void;
}

class CreditCardPayment implements PaymentMethod
{
    public function pay(float $amount): void
    {
        echo "Paid ${amount} using Credit Card";
    }
}

class PayPalPayment implements PaymentMethod
{
    public function pay(float $amount): void
    {
        echo "Paid ${amount} via PayPal";
    }
}

class CryptoPayment implements PaymentMethod
{
    public function pay(float $amount): void
    {
        echo "Paid ${amount} in Bitcoin";
    }
}

function processPayment(PaymentMethod $method, float $amount): void {
    $method->pay($amount);
}

processPayment(new CreditCardPayment(), 100.0);  // Paid $100 using Credit Card
processPayment(new PayPalPayment(), 50.5);       // Paid $50.5 via PayPal
processPayment(new CryptoPayment(), 250.0);      // Paid $250 in Bitcoin

Abstraction: Abstract classes and interfaces declare an API without providing full implementation. Use abstract class for partial implementations, interface for pure contracts.

interface Renderer
{
    public function render(array $data): string;
}

class HtmlRenderer implements Renderer
{
    public function render(array $data): string
    {
        // produce HTML
        return '<pre>' . htmlspecialchars(json_encode($data, JSON_THROW_ON_ERROR)) . '</pre>';
    }
}

Properties

Property Type Declarations

Typed properties enforce runtime type rules and reduce bugs.

class Product
{
    public int $id;
    public ?string $title = null; // nullable
}

Union Types

You can declare union types:

class Example
{
    public int|string $id;
}

Readonly Properties

readonly properties can be set once (usually in the constructor) and then cannot be reassigned.

class User
{
    public readonly int $id;

    public function __construct(int $id)
    {
        $this->id = $id;
    }
}

Constructor Property Promotion

You can declare class properties directly in the constructor parameter list:

class DTO
{
    public function __construct(
        public int $id,
        private string $name,
        protected ?DateTimeImmutable $createdAt = null
    ) {}
}

This declares the properties and initialises them - less boilerplate.

Property Hooks

Property hooks (sometimes called property accessors) let you define get and/or set behavior on a particular property (not via __get/__set magic for all unknowns). Hooks allow virtual properties (no actual storage) and fine control over per-property behavior.

Key points:

  • Hooks are per-property get / set blocks.
  • Properties with hooks can be virtual (no backing storage) or backed (store a value).
  • Hooks are incompatible with readonly (i.e., you cannot have readonly + hooks on same property).
  • A child hook may access the parent hook or parent's storage via parent::$prop::get() / parent::$prop::set() syntax.
  • Asymmetric visibility works with hooks (you can define different read/write visibilities).
class Example
{
    private bool $modified = false;

    public string $foo = 'default value' {
        get {
            if ($this->modified) {
                return $this->foo . ' (modified)';
            }

            return $this->foo;
        }
        set(string $value) {
            $this->foo = strtolower($value);
            $this->modified = true;
        }
    }
}

$example = new Example();
$example->foo = 'changed';

print $example->foo; // changed (modified)

Class Constants

 

test


Source: Orkhan Alishov's notes