Launch offer
Business website $150 USD Custom plugin $200 USD Ready in 5 days
Get a quote
OOP

OOP Complete Tutorial: Object-Oriented Programming (65 Topics with Code)

Complete OOP tutorial covering classes, inheritance, polymorphism, SOLID, design patterns, MVC, and OOP in PHP, WordPress, and Laravel — with practical code examples.

OOP Complete Tutorial: Object-Oriented Programming (65 Topics with Code) — a practical guide to OOP tutorial with clear examples you can reuse in real projects.

This complete Object-Oriented Programming (OOP) tutorial covers 65 topics — from classes and inheritance to SOLID, design patterns, MVC, and OOP in PHP, WordPress, and Laravel. Beginner-friendly with practical PHP code.

Course roadmap

1. Introduction to OOP

OOP helps you model software as interacting objects. This series uses PHP examples and connects OOP to WordPress plugins/themes and Laravel.

  1. Learn classes, objects, and encapsulation first.
  2. Practice inheritance and interfaces.
  3. Apply SOLID and build the final PHP project.

Learning path

Classes/objects → encapsulation/inheritance
Polymorphism/abstraction → SOLID
Patterns/MVC → PHP apps, WP, Laravel
Final OOP PHP project

2. What is Object-Oriented Programming?

In OOP, you define classes (blueprints) and create objects (instances) that hold state (properties) and behavior (methods).

Core idea

class User {
    public string $name;
    public function greet(): string {
        return 'Hi ' . $this->name;
    }
}

$u = new User();
$u->name = 'Asha';
echo $u->greet();

3. Procedural Programming vs OOP

Procedural code focuses on functions and data separately. OOP groups related data and behavior, which scales better for larger apps.

Same task, two styles

// Procedural
function user_greet(string $name): string {
    return 'Hi ' . $name;
}

// OOP
class Greeter {
    public function __construct(private string $name) {}
    public function greet(): string { return 'Hi ' . $this->name; }
}

4. Advantages of OOP

OOP improves code organization through encapsulation, reuse via inheritance/composition, and flexible designs through polymorphism.

Key advantages

- Modularity
- Reusability
- Easier maintenance
- Better domain modeling
- Testable units (classes/services)

5. Classes and Objects

A class defines structure. An object is a live instance created with `new` that uses that structure.

Class vs object

class Product {}
$a = new Product(); // object
$b = new Product(); // another object

6. Creating a Class

Use clear class names (StudlyCase). Keep one main responsibility per class when possible.

Create a class

class Invoice {
    public string $number;
    public float $total = 0.0;

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

7. Creating Objects

Each object has its own property values even if they share the same class.

Instantiate

$inv = new Invoice();
$inv->number = 'INV-1001';
$inv->add(250);
echo $inv->total;

8. Properties and Attributes

Properties hold data. Prefer typed properties in modern PHP and initialize them safely.

Typed properties

class Article {
    public string $title;
    public bool $published = false;
}

9. Methods and Functions

Methods can read/update properties and return values. Keep methods focused and named clearly.

Instance method

class Counter {
    private int $count = 0;
    public function increment(): int {
        return ++$this->count;
    }
}

10. Constructors in OOP

Constructors set required state. In modern PHP, constructor property promotion keeps code short.

Constructor promotion

class User {
    public function __construct(
        public string $name,
        public string $email,
    ) {}
}

$u = new User('Ravi', 'ravi@example.com');

11. Destructors in OOP

Destructors are less common in PHP web apps (request lifecycle is short), but useful for closing resources in long-running CLI processes.

Destructor

class FileLogger {
    public function __destruct() {
        // close handles / flush buffers
    }
}

12. The $this Keyword

Inside an instance method, `$this` refers to the object the method was called on.

$this usage

class Account {
    private float $balance = 0;
    public function deposit(float $amount): void {
        $this->balance += $amount;
    }
    public function getBalance(): float {
        return $this->balance;
    }
}

13. Access Modifiers in OOP

Access modifiers are a core encapsulation tool — they hide internal details and expose a safe API.

Visibility overview

public    → accessible everywhere
protected → class + subclasses
private   → only inside the same class

14. Public, Private and Protected

Default to private/protected for state; expose only what callers need via public methods.

Visibility example

class BankAccount {
    private float $balance = 0;
    public function deposit(float $amount): void {
        if ($amount <= 0) throw new InvalidArgumentException('Invalid amount');
        $this->balance += $amount;
    }
}

15. Encapsulation in OOP

Encapsulation protects invariants (rules). Callers use methods instead of changing properties directly.

Encapsulated API

class Temperature {
    public function __construct(private float $celsius) {}
    public function toFahrenheit(): float {
        return ($this->celsius * 9 / 5) + 32;
    }
}

16. Inheritance in OOP

Inheritance models “is-a” relationships (Dog is an Animal). Prefer composition when “has-a” fits better.

extends

class Animal {
    public function speak(): string { return '...'; }
}
class Dog extends Animal {
    public function speak(): string { return 'Woof'; }
}

17. Types of Inheritance

PHP supports single class inheritance and multiple interfaces/traits to cover many multiple-inheritance use cases.

Inheritance types

Single → one parent
Multilevel → chain of parents
Hierarchical → many children from one parent
Multiple → many parents (via interfaces/traits in PHP)

18. Single Inheritance

A class may extend only one parent class in PHP. Use interfaces/traits for additional reuse.

Single parent

class Vehicle {}
class Car extends Vehicle {}

19. Multilevel Inheritance

Keep chains short. Deep hierarchies become hard to understand and change.

Multilevel

class Employee {}
class Manager extends Employee {}
class Director extends Manager {}

20. Hierarchical Inheritance

Hierarchical inheritance is common for payment gateways, notifiers, and shape hierarchies.

One parent, many children

class Shape {}
class Circle extends Shape {}
class Square extends Shape {}

21. Multiple Inheritance

PHP does not allow extending multiple classes. Implement multiple interfaces and use traits for shared code.

Interfaces + trait

interface Loggable { public function log(string $msg): void; }
interface Cacheable { public function cacheKey(): string; }
trait WritesLog {
    public function log(string $msg): void { echo $msg; }
}
class Report implements Loggable, Cacheable {
    use WritesLog;
    public function cacheKey(): string { return 'report'; }
}

22. Polymorphism in OOP

Polymorphism lets you write code against interfaces/base types while concrete classes decide the behavior.

Polymorphic loop

interface Notifier { public function send(string $to): void; }
class EmailNotifier implements Notifier {
    public function send(string $to): void { /* email */ }
}
class SmsNotifier implements Notifier {
    public function send(string $to): void { /* sms */ }
}
/** @param Notifier[] $notifiers */
function notifyAll(array $notifiers, string $to): void {
    foreach ($notifiers as $n) { $n->send($to); }
}

23. Method Overloading

Classic overloading (same method name, different signatures) is not native in PHP. Use default args, variadics, or separate methods instead.

PHP-style flexibility

class Math {
    public function sum(int ...$nums): int {
        return array_sum($nums);
    }
}
echo (new Math())->sum(1, 2, 3);

24. Method Overriding

Overriding customizes inherited behavior. Call `parent::method()` when you need to extend rather than fully replace.

Override

class Controller {
    public function handle(): string { return 'base'; }
}
class ApiController extends Controller {
    public function handle(): string { return 'json'; }
}

25. Abstraction in OOP

Abstraction focuses on “what” an object does. Abstract classes and interfaces help define clean contracts.

Abstraction idea

Caller: $gateway->charge(100)
Hidden: HTTP, signatures, retries, logging

26. Abstract Classes

Abstract classes can include shared code plus abstract methods children must implement.

Abstract class

abstract class PaymentGateway {
    abstract public function charge(int $amount): bool;
    public function currency(): string { return 'INR'; }
}
class StripeGateway extends PaymentGateway {
    public function charge(int $amount): bool { return true; }
}

27. Interfaces in OOP

Interfaces are ideal for polymorphism and dependency injection. A class can implement many interfaces.

Interface

interface Logger {
    public function info(string $message): void;
}
class FileLogger implements Logger {
    public function info(string $message): void { file_put_contents('app.log', $message.PHP_EOL, FILE_APPEND); }
}

28. Traits in PHP OOP

Traits solve code reuse without multiple class inheritance. Watch for conflict resolution with `insteadof`/`as`.

Trait usage

trait HasTimestamps {
    public function touch(): void { $this->updatedAt = new DateTimeImmutable(); }
}
class Post {
    use HasTimestamps;
    public ?DateTimeImmutable $updatedAt = null;
}

29. Static Properties and Methods

Static members belong to the class, not an instance. Overuse can hurt testability — prefer dependency injection for services.

Static example

class IdGenerator {
    private static int $last = 0;
    public static function next(): int {
        return ++self::$last;
    }
}
echo IdGenerator::next();

30. Constants in Classes

Class constants are useful for statuses, config keys, and fixed options.

Class const

class OrderStatus {
    public const PENDING = 'pending';
    public const PAID = 'paid';
}
echo OrderStatus::PAID;

31. Final Classes and Methods

Use `final` to protect critical classes/methods from unsafe extension.

final examples

final class Money {
    public function __construct(public int $cents) {}
}
class Service {
    final public function boot(): void {}
}

32. Parent and Child Classes

Children inherit members and can add/override behavior while staying substitutable for the parent type.

Parent/child

class User { public function role(): string { return 'user'; } }
class Admin extends User { public function role(): string { return 'admin'; } }

33. The parent Keyword

`parent::` accesses the overridden implementation in the parent class.

parent:: usage

class Model {
    public function __construct(public array $attrs = []) {}
}
class Post extends Model {
    public function __construct(array $attrs = []) {
        parent::__construct($attrs);
    }
}

34. The self Keyword

`self` refers to the class where it is written. For late static binding (inheritance-aware), use `static::`.

self vs static

class Base {
    public static function who(): string { return self::class; }
    public static function whoLate(): string { return static::class; }
}
class Child extends Base {}
echo Child::who();     // Base
echo Child::whoLate(); // Child

35. instanceof in PHP

`instanceof` works with classes and interfaces. Prefer type hints when possible instead of frequent runtime checks.

instanceof

function dump($value): void {
    if ($value instanceof DateTimeInterface) {
        echo $value->format('c');
    }
}

36. Getters and Setters

Getters/setters validate changes and preserve encapsulation. In modern PHP, consider readonly properties when mutation is unnecessary.

Getter/setter

class Profile {
    public function __construct(private string $email) {}
    public function getEmail(): string { return $this->email; }
    public function setEmail(string $email): void {
        if (! filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Invalid email');
        }
        $this->email = $email;
    }
}

37. Dependency Injection

Dependency Injection (DI) improves testing and flexibility. Inject interfaces, not concrete classes, when useful.

Constructor injection

interface Mailer { public function send(string $to, string $body): void; }
class WelcomeService {
    public function __construct(private Mailer $mailer) {}
    public function welcome(string $email): void {
        $this->mailer->send($email, 'Welcome!');
    }
}

38. Composition vs Inheritance

Composition builds behavior by combining objects. It usually reduces fragile base-class problems.

Composition

class Engine { public function start(): string { return 'vroom'; } }
class Car {
    public function __construct(private Engine $engine) {}
    public function start(): string { return $this->engine->start(); }
}

39. Association, Aggregation and Composition

Association links objects. Aggregation is a weak “has-a”. Composition is a strong “owns-a” lifecycle relationship.

Relationship summary

Association → uses
Aggregation → has (parts can live independently)
Composition → owns (parts die with the whole)

40. Object Cloning

Default cloning is shallow. Implement `__clone` for deep copies of nested objects.

clone + __clone

class Cart {
    public function __construct(public array $items) {}
    public function __clone(): void {
        // adjust cloned state if needed
    }
}
$a = new Cart(['book']);
$b = clone $a;

41. Magic Methods in PHP OOP

Magic methods are powerful but can hide logic. Use them deliberately and document behavior.

__toString and __invoke

class Money {
    public function __construct(private int $cents) {}
    public function __toString(): string { return ($this->cents / 100) . ' INR'; }
}
echo new Money(1999);

42. Namespaces in PHP

Namespaces map well to folder structures and Composer PSR-4 autoloading.

Namespace example

namespace AppBilling;

class Invoice {}

// elsewhere:
use AppBillingInvoice;
$invoice = new Invoice();

43. Autoloading in PHP

Autoloading removes endless `require` statements and is standard in modern PHP apps.

Composer PSR-4

{
  "autoload": {
    "psr-4": {
      "App": "src/"
    }
  }
}

44. PSR Standards

Key PSRs: PSR-1/PSR-12 coding style, PSR-4 autoloading, PSR-3 logging, PSR-7 HTTP messages, PSR-11 containers.

Useful PSRs

PSR-12 → style
PSR-4 → autoloading
PSR-3 → logger interface
PSR-7/15 → HTTP & middleware
PSR-11 → container

45. Exception Handling in OOP

Create domain exceptions, throw early, catch at boundaries, and avoid empty catch blocks.

Custom exception

class InsufficientFunds extends RuntimeException {}
class Wallet {
    public function __construct(private int $cents) {}
    public function pay(int $amount): void {
        if ($amount > $this->cents) throw new InsufficientFunds('Not enough funds');
        $this->cents -= $amount;
    }
}

46. SOLID Principles

SOLID helps keep classes focused, extensible, and loosely coupled — especially important as projects grow.

SOLID map

S — Single Responsibility
O — Open/Closed
L — Liskov Substitution
I — Interface Segregation
D — Dependency Inversion

47. Single Responsibility Principle

SRP reduces tangled code. Split reporting, persistence, and emailing into separate classes.

SRP example

class OrderRepository { public function save(Order $order): void {} }
class OrderMailer { public function sendConfirmation(Order $order): void {} }

48. Open/Closed Principle

Add new behavior via new classes implementing interfaces, instead of editing giant switch statements repeatedly.

OCP sketch

interface Discount { public function apply(float $total): float; }
class PercentageDiscount implements Discount {
    public function __construct(private float $percent) {}
    public function apply(float $total): float { return $total * (1 - $this->percent / 100); }
}

49. Liskov Substitution Principle

If code expects a `Bird`, a subclass should not surprise it (e.g., by throwing on `fly()` when flying was assumed).

LSP tip

Subtypes must honor parent contracts
Don't strengthen preconditions unexpectedly
Prefer separate interfaces when behaviors diverge

50. Interface Segregation Principle

Many specific interfaces are better than one fat interface.

ISP example

interface CanPrint { public function print(): void; }
interface CanScan { public function scan(): void; }
class SimplePrinter implements CanPrint {
    public function print(): void {}
}

51. Dependency Inversion Principle

DIP is the principle behind good dependency injection and testable architecture.

DIP

interface UserRepository { public function find(int $id): ?User; }
class UserService {
    public function __construct(private UserRepository $users) {}
}

52. Design Patterns Introduction

Patterns are tools, not goals. Learn a few deeply (Factory, Strategy, Repository, Adapter) before collecting many.

Pattern categories

Creational → Factory, Singleton
Structural → Adapter, Decorator
Behavioral → Strategy, Observer

53. Factory Pattern

Factories help when creation logic is non-trivial or when you want to return interface types.

Simple factory

class NotifierFactory {
    public static function make(string $channel): Notifier {
        return match ($channel) {
            'email' => new EmailNotifier(),
            'sms' => new SmsNotifier(),
            default => throw new InvalidArgumentException('Unknown channel'),
        };
    }
}

54. Singleton Pattern

Singleton restricts a class to one instance. It can hide dependencies and complicate testing — use sparingly.

Singleton sketch

final class Config {
    private static ?self $instance = null;
    private function __construct() {}
    public static function getInstance(): self {
        return self::$instance ??= new self();
    }
}

55. Repository Pattern

Repositories make services database-agnostic and easier to fake in tests.

Repository interface

interface PostRepository {
    public function find(int $id): ?Post;
    public function save(Post $post): void;
}
class MysqlPostRepository implements PostRepository {
    public function find(int $id): ?Post { /* query */ return null; }
    public function save(Post $post): void { /* insert/update */ }
}

56. MVC Architecture

MVC keeps UI, request handling, and domain/data logic separated — used by Laravel, many PHP apps, and inspired WP patterns.

MVC roles

Model → data & business rules
View → presentation
Controller → request flow / input mapping

57. OOP with Database

Use connection services, repositories/models, and entities/DTOs to keep SQL organized.

DB wrapper sketch

class Database {
    public function __construct(private PDO $pdo) {}
    public function fetchAll(string $sql, array $params = []): array {
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

58. OOP with MySQL

PDO is object-oriented and supports safe parameterized queries for MySQL.

PDO connection

$pdo = new PDO(
    'mysql:host=127.0.0.1;dbname=app;charset=utf8mb4',
    'root',
    '',
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([1]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

59. OOP in PHP

PHP’s OOP model is mature — use typed properties, return types, interfaces, and Composer autoloading as defaults.

Modern PHP OOP

enum Status: string { case Draft = 'draft'; case Published = 'published'; }
final class Post {
    public function __construct(
        public readonly string $title,
        public Status $status = Status::Draft,
    ) {}
}

60. OOP in WordPress Plugin Development

OOP plugins are easier to maintain: one class for admin, one for REST, one for CPT registration, bootstrapped from the main plugin file.

Plugin class bootstrap

namespace AcmeTools;

final class Plugin {
    public function boot(): void {
        add_action('init', [$this, 'register']);
    }
    public function register(): void {
        // CPT, shortcodes, etc.
    }
}

(new Plugin())->boot();

61. OOP in WordPress Theme Development

Even classic themes benefit from OOP helpers and setup classes instead of a giant functions.php.

Theme setup class

final class ThemeSetup {
    public function register(): void {
        add_action('after_setup_theme', [$this, 'supports']);
        add_action('wp_enqueue_scripts', [$this, 'assets']);
    }
    public function supports(): void {
        add_theme_support('title-tag');
    }
    public function assets(): void {
        wp_enqueue_style('theme', get_stylesheet_uri(), [], '1.0.0');
    }
}

62. OOP in Laravel

Laravel is built around dependency injection and interfaces (contracts). Your app code should follow the same OOP style.

Laravel-style injection

// app/Services/InvoiceService.php
namespace AppServices;

class InvoiceService {
    public function __construct(private InvoiceRepository $invoices) {}
    public function dueSoon(): array {
        return $this->invoices->dueWithinDays(7);
    }
}

63. OOP Interview Questions

Be ready to explain encapsulation, inheritance vs composition, interfaces vs abstract classes, and SOLID with examples.

Sample Q&A

Q: Interface vs abstract class?
A: Interface = contract only (mostly); abstract class can share code.

Q: Overloading vs overriding?
A: Overloading = same name different signatures (limited in PHP); overriding = redefine parent method.

Q: Why DI?
A: Loose coupling + easier testing.

Q: Composition vs inheritance?
A: Prefer has-a composition for flexibility.

64. OOP Practical Examples

Practical examples connect theory to code you can reuse in apps and interviews.

Mini cart example

class CartItem {
    public function __construct(public string $name, public int $priceCents, public int $qty = 1) {}
    public function lineTotal(): int { return $this->priceCents * $this->qty; }
}
class Cart {
    /** @var CartItem[] */
    private array $items = [];
    public function add(CartItem $item): void { $this->items[] = $item; }
    public function total(): int {
        return array_sum(array_map(fn (CartItem $i) => $i->lineTotal(), $this->items));
    }
}

65. Final Project – Complete OOP-Based PHP Application

Create a small application (task manager or blog admin) using namespaces, Composer autoload, PDO repositories, services, and simple controllers/views.

  1. Define the domain (tasks/posts/users).
  2. Implement repositories and services.
  3. Wire a front controller with simple routing.
  4. Add validation, auth, and README.

Final project scope

1. Composer + PSR-4 namespaces
2. PDO Database class
3. Entities + Repository interfaces
4. Services with constructor DI
5. Controllers + simple PHP views (MVC)
6. Exceptions + validation objects
7. Auth session service
8. README + UML/class list

Suggested structure

public/index.php
src/Controller
src/Domain
src/Repository
src/Service
src/Support
views/
composer.json

Conclusion

You now have a complete OOP foundation: classes, encapsulation, inheritance, polymorphism, SOLID, and practical patterns. Apply it in PHP applications, WordPress plugins/themes, and Laravel — then finish the final OOP PHP project.

Leave a reply

Your email address will not be published. Required fields are marked *