PHP & Laravel — Zero to Hero Episode 14: Interfaces, Abstract Classes, and Namespaces — The Last Core PHP Concepts Before Laravel

What Are We Doing in This Post?

This is the final Core PHP episode. After this, we start Laravel.

In Episode 13 we learned classes, objects, inheritance, and encapsulation. Those are the foundations. This episode covers three more OOP concepts that are used everywhere in Laravel's source code — interfaces, abstract classes, and namespaces.

You will not build a full Laravel application using these directly as a beginner. But you will encounter them constantly while reading Laravel code. Understanding them now means Laravel will make sense immediately instead of feeling like an alien codebase.

Let us finish Core PHP strong.


Part 1 — Interfaces

The Problem Interfaces Solve

Imagine you are building a payment system. Your application needs to support multiple payment gateways — Razorpay, PayPal, and Stripe. Each gateway has different internal code, different API calls, different response formats.

But from your application's point of view, you want to treat them all the same way. You want to call charge(), refund(), and get_transaction_id() on any of them without caring which one you are using.

How do you guarantee that every payment gateway class has exactly these methods? You use an interface.

What is an Interface?

An interface is a contract. It says: any class that implements this interface must have these specific methods. The interface does not provide any implementation — just the list of method signatures that must exist.

Real world analogy: Think of an interface like a job description. The job description for a Driver says: must be able to start the vehicle, steer, and stop. Whether you are driving a car, a bus, or a truck — different vehicles, different internal mechanics — you must be able to do all three things. The job description enforces the contract without caring how each vehicle implements it internally.


    <?php

    interface PaymentGateway
    {
        public function charge($amount, $currency);
        public function refund($transaction_id);
        public function get_transaction_id();
    }

An interface only contains method signatures — the method name, parameters, and return nothing. No code inside the methods. No properties. Just the contract.

Implementing an Interface


    <?php

    interface PaymentGateway
    {
        public function charge($amount, $currency);
        public function refund($transaction_id);
        public function get_transaction_id();
    }

    class RazorpayGateway implements PaymentGateway
    {

        private $transaction_id;

        public function charge($amount, $currency)
        {
            $this->transaction_id = "RPY-" . rand(100000, 999999);
            echo "Charged Rs. $amount via Razorpay. Transaction: $this->transaction_id";
            echo "<br>";
        }

        public function refund($transaction_id)
        {
            echo "Refund initiated on Razorpay for transaction: $transaction_id";
            echo "<br>";
        }

        public function get_transaction_id()
        {
            return $this->transaction_id;
        }
    }

    class PayPalGateway implements PaymentGateway
    {

        private $transaction_id;

        public function charge($amount, $currency)
        {
            $this->transaction_id = "PPL-" . rand(100000, 999999);
            echo "Charged $currency $amount via PayPal. Transaction: $this->transaction_id";
            echo "<br>";
        }

        public function refund($transaction_id)
        {
            echo "Refund initiated on PayPal for transaction: $transaction_id";
            echo "<br>";
        }

        public function get_transaction_id()
        {
            return $this->transaction_id;
        }
    }

    function process_payment(PaymentGateway $gateway, $amount)
    {
        $gateway->charge($amount, "INR");
        echo "Transaction ID: " . $gateway->get_transaction_id();
        echo "<br>";
    }

    $razorpay = new RazorpayGateway();
    $paypal   = new PayPalGateway();

    process_payment($razorpay, 1999);
    process_payment($paypal, 2999);

Output:

Charged Rs. 1999 via Razorpay. Transaction: RPY-766958
Transaction ID: RPY-766958
Charged INR 2999 via PayPal. Transaction: PPL-998840
Transaction ID: PPL-998840

The process_payment() function accepts any object that implements PaymentGateway. It does not care whether it is Razorpay or PayPal — it just knows both of them have the charge() and get_transaction_id() methods because the interface guarantees it.

If you create a new StripeGateway class but forget to implement the refund() method, PHP throws a fatal error immediately. The interface enforces the contract strictly.

This is called polymorphism — different classes being used interchangeably because they all follow the same interface contract.

In Laravel: interfaces are used everywhere. Laravel's Cache, Mail, Queue, and Storage systems all work through interfaces. This is why you can switch from file-based caching to Redis caching by changing one line in a config file — both implement the same interface.


Part 2 — Abstract Classes

The Difference Between Interface and Abstract Class

An interface is a pure contract — no implementation at all. An abstract class sits in the middle — it can have some implemented methods and some unimplemented methods.

Think of it this way. An interface says: you must have these methods, figure out the implementation yourself. An abstract class says: here are some methods I have already implemented for you, but you must implement these specific ones yourself.

Real world analogy: An abstract class is like a house blueprint that already has the foundation and walls drawn in — the structural parts are fixed. But the interior layout, the rooms, the furniture placement — those are left for the specific house design to decide. You cannot build directly from an abstract blueprint. You must extend it and fill in the missing pieces.


    <?php

    abstract class Shape
    {

        protected $color;

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

        abstract public function area();
        abstract public function perimeter();

        public function describe()
        {
            echo "This is a $this->color shape.";
            echo "<br>";
            echo "Area: " . $this->area();
            echo "<br>";
            echo "Perimeter: " . $this->perimeter();
            echo "<br>";
        }
    }

    class Circle extends Shape
    {

        private $radius;

        public function __construct($color, $radius)
        {
            parent::__construct($color);
            $this->radius = $radius;
        }

        public function area()
        {
            return round(M_PI * $this->radius ** 2, 2);
        }

        public function perimeter()
        {
            return round(2 * M_PI * $this->radius, 2);
        }
    }

    class Rectangle extends Shape
    {

        private $width;
        private $height;

        public function __construct($color, $width, $height)
        {
            parent::__construct($color);
            $this->width  = $width;
            $this->height = $height;
        }

        public function area()
        {
            return $this->width * $this->height;
        }

        public function perimeter()
        {
            return 2 * ($this->width + $this->height);
        }
    }

    $circle    = new Circle("red", 7);
    $rectangle = new Rectangle("blue", 10, 5);

    $circle->describe();
    echo "<br>";
    $rectangle->describe();

Output:

This is a red shape.
Area: 153.94
Perimeter: 43.98

This is a blue shape.
Area: 50
Perimeter: 30

The abstract keyword on area() and perimeter() means: every class that extends Shape must implement these methods. Shape provides the shared describe() method — both Circle and Rectangle get it for free through inheritance.

You cannot do new Shape() directly — PHP will throw an error. You can only instantiate the concrete child classes.

Interface vs Abstract Class — When to Use Which

Use an interface when you want to define a contract that completely unrelated classes must follow. A Car and a Bird are very different things — but both can implement a Moveable interface.

Use an abstract class when you have a group of related classes that share some common implementation but must each provide specific behavior. Circle and Rectangle are both Shapes — they share the describe() method but each calculates area differently.

In Laravel: the base Controller class is abstract. Eloquent's Model class has abstract-like behavior. Middleware classes implement an interface called Handle. You will see both constantly.


Part 3 — Namespaces

The Problem Namespaces Solve

As a project grows, you end up with hundreds of PHP files and classes. Name conflicts become a real problem. What if you have a User class in your authentication system and another User class in your admin panel? PHP cannot have two classes with the same name loaded at the same time.

Real world analogy: Think of namespaces like addresses. There can be a "Main Street" in Delhi and a "Main Street" in Mumbai — same street name, two completely different locations. The city name distinguishes them. Namespaces work the same way — they give your classes a unique address so they never conflict with each other.


    <?php

    namespace App\Auth;

    class User
    {

        public $name;

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

        public function get_role()
        {
            return "Authenticated User";
        }
    }

    ?>


    <?php

    namespace App\Admin;

    class User
    {

        public $name;

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

        public function get_role()
        {
            return "Administrator";
        }
    }

    ?>

Both files have a class called User. But they live in different namespaces — App\Auth and App\Admin. PHP treats them as completely separate classes.

Using Namespaced Classes


    <?php

    require_once "AuthUser.php";
    require_once "AdminUser.php";

    use App\Auth\User as AuthUser;
    use App\Admin\User as AdminUser;

    $auth_user  = new AuthUser("Gagan");
    $admin_user = new AdminUser("Rahul");

    echo $auth_user->name . "" . $auth_user->get_role();
    echo "<br>";
    echo $admin_user->name . "" . $admin_user->get_role();

Output:

Gagan — Authenticated User Rahul — Administrator

The use keyword imports a namespaced class so you can refer to it by a shorter name. as gives it an alias when two classes share the same short name.

In Laravel: every file starts with namespace App\Http\Controllers or namespace App\Models or similar. Every time you open a Laravel controller or model, you see use statements at the top importing other classes. Now you know exactly what those mean.


Part 4 — Autoloading With Composer

Right now we use require_once to include every file we need. In a large project with hundreds of classes, this becomes unmanageable — you would need dozens of require_once statements at the top of every file.

Autoloading solves this. With autoloading, PHP automatically loads the right class file the moment you use that class — no manual require_once needed.

Composer is PHP's dependency manager and it handles autoloading for us. Laravel uses Composer — you will install it before starting Laravel. Let us set it up now so you are ready.

Install Composer:

Go to getcomposer.org and download the Windows installer. Run it and follow the steps. After installation, open a new Command Prompt and type:

composer --version

You should see a version number. Composer is installed.

Setting Up Autoloading in a Project:

In your phplearning folder, create a file called composer.json:

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

This tells Composer: any class in the App namespace should be loaded from the src/ folder.

Create the folder src/ inside phplearning. Now create a class file src/Product.php:


    <?php

    namespace App;

    class Product
    {

        public $name;
        public $price;

        public function __construct($name, $price)
        {
            $this->name  = $name;
            $this->price = $price;
        }

        public function get_formatted_price()
        {
            return "Rs. " . number_format($this->price, 2);
        }
    }

Now open Command Prompt, navigate to your phplearning folder, and run:

composer dump-autoload

Composer generates an autoload file. Now create index_autoload.php in phplearning:


    <?php

    require_once "vendor/autoload.php";

    use App\Product;

    $product = new Product("Mechanical Keyboard", 2499);
    echo $product->name . "" . $product->get_formatted_price();

Visit http://localhost:8080/phplearning/index_autoload.php

Output: Mechanical Keyboard — Rs. 2,499.00

No manual require_once for the Product class. Composer loaded it automatically the moment you used it. This is exactly how Laravel works — you never manually include class files in Laravel. Composer's autoloader handles everything.

PSR-4 is a PHP standard that maps namespaces to folder structures. App\Models\User maps to src/Models/User.php. App\Http\Controllers\UserController maps to src/Http/Controllers/UserController.php. Laravel follows this standard throughout its entire codebase.


Putting It All Together — What You Now Know

Let us take a step back and look at what you have learned across all 14 Core PHP episodes.

Variables, data types, operators — how PHP stores and works with data.

Conditionals and loops — how PHP makes decisions and repeats tasks.

Arrays and functions — how PHP manages collections and reusable logic.

Forms, sessions, cookies — how PHP interacts with users and remembers state.

MySQL with PDO and prepared statements — how PHP stores and retrieves data permanently.

OOP — classes, objects, constructors, access modifiers, encapsulation, inheritance, interfaces, abstract classes.

Namespaces and autoloading — how PHP organizes large codebases.

This is a complete foundation. Most developers who struggle with Laravel struggled because they skipped this foundation. You did not skip it.


What Did We Learn in This Post?

Interfaces define a contract — a list of methods that any implementing class must provide. They enable polymorphism — different classes used interchangeably through a shared contract.

Abstract classes sit between interfaces and regular classes — they can have both implemented and unimplemented methods. You cannot instantiate an abstract class directly.

Use an interface for unrelated classes sharing a behavior contract. Use an abstract class for related classes sharing partial implementation.

Namespaces give classes a unique address to prevent naming conflicts in large projects. The use keyword imports namespaced classes. Laravel uses namespaces in every single file.

Composer manages PHP dependencies and handles autoloading via PSR-4. Every class in the right namespace and folder is loaded automatically — no manual require_once needed. Laravel is entirely Composer-based.


What is Coming in Episode 15?

Episode 15 is a major milestone. Core PHP is complete. We start Laravel.

We will install Laravel using Composer, understand what gets created, start the development server, and explore the folder structure in detail. Every folder, every file — what it is, what it does, and why it exists.

This is where everything accelerates. The foundation is solid. Now we build on it.

See you in the next one.


Next Episode: Installing Laravel and Understanding the Project Structure

This is Episode 14 of the PHP and Laravel — Zero to Hero series.


PHP & Laravel — Zero to Hero Episode 13: Object Oriented PHP — Classes, Objects, and the Foundation of Laravel

What Are We Doing in This Post?

Every episode so far has been procedural PHP — code that runs from top to bottom, one line after another. Functions helped us organize and reuse code. But there is a more powerful way to structure programs.

Object Oriented Programming — OOP — is a completely different way of thinking about code. Instead of writing a series of instructions, you model your program around real-world things called objects.

This is not optional knowledge. Laravel is built entirely on OOP. Every single feature of Laravel — controllers, models, middleware, requests, responses — is a class. If you do not understand OOP, Laravel will feel like magic you cannot control. After this episode, it will feel like logic you can read and write yourself.


The Problem With Procedural Code

Imagine you are building a school management system. You need to manage students. Each student has a name, age, grade, and email. You need functions to enroll them, calculate their GPA, and send them notifications.

In procedural PHP you would have scattered arrays and functions all over the place:


    <?php

    $student1_name  = "Gagan";
    $student1_age   = 20;
    $student1_grade = "A";

    $student2_name  = "Rahul";
    $student2_age   = 22;
    $student2_grade = "B";

    function calculate_gpa($grade)
    {
        if ($grade == "A") return 4.0;
        if ($grade == "B") return 3.0;
        return 0.0;
    }

This becomes unmanageable fast. Add 50 students and this is chaos. There is no connection between the data and the functions that work on it.

OOP solves this by bundling related data and functions together into a single unit called a class.


What is a Class?

A class is a blueprint. It defines what a thing is and what it can do.

Real world analogy: Think of a class like an architectural blueprint for a house. The blueprint describes how many rooms the house has, where the doors are, what materials to use. The blueprint itself is not a house — it is the plan. When you actually build a house from that blueprint, that built house is an object. You can build a hundred different houses from the same blueprint — each one is a separate object, but all follow the same plan.

In PHP: the class is the blueprint. The object is the actual instance created from that blueprint.


    <?php

    class Student
    {

        public $name;
        public $age;
        public $grade;

        public function greet()
        {
            echo "Hello, my name is $this->name and I am $this->age years old.";
        }

        public function calculate_gpa()
        {
            if ($this->grade == "A") return 4.0;
            if ($this->grade == "B") return 3.0;
            if ($this->grade == "C") return 2.0;
            return 0.0;
        }
    }

The variables inside a class are called properties. The functions inside a class are called methods. Together they define what a Student is and what a Student can do.

$this is a special variable inside a class that refers to the current object — the specific instance of the class that is running the method. When you call a method on an object, $this gives that method access to the object's own properties.


Creating Objects — Instances of a Class


    <?php

    $student1 = new Student();
    $student1->name  = "Gagan";
    $student1->age   = 20;
    $student1->grade = "A";

    $student2 = new Student();
    $student2->name  = "Rahul";
    $student2->age   = 22;
    $student2->grade = "B";

    $student1->greet();
    echo "<br>";
    echo "GPA: " . $student1->calculate_gpa();
    echo "<br>";

    $student2->greet();
    echo "<br>";
    echo "GPA: " . $student2->calculate_gpa();

Output:

Hello, my name is Gagan and I am 20 years old. GPA: 4.0 Hello, my name is Rahul and I am 22 years old. GPA: 3.0

new Student() creates a new object from the Student blueprint. The -> operator accesses properties and methods on an object.

$student1 and $student2 are two completely separate objects. They both follow the Student blueprint but hold completely different data independently.


The Constructor — Setting Up an Object at Birth

Setting properties one by one after creating an object is repetitive. PHP gives you a special method called __construct() — the constructor. It runs automatically the moment you create a new object with new.


    <?php

    class Student
    {

        public $name;
        public $age;
        public $grade;

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

        public function greet()
        {
            echo "Hello, my name is $this->name.";
        }

        public function calculate_gpa()
        {
            if ($this->grade == "A") return 4.0;
            if ($this->grade == "B") return 3.0;
            if ($this->grade == "C") return 2.0;
            return 0.0;
        }

        public function get_info()
        {
            return "$this->name | Age: $this->age | Grade: $this->grade | GPA: " . $this->calculate_gpa();
        }
    }

    $student1 = new Student("Gagan", 20, "A");
    $student2 = new Student("Rahul", 22, "B");
    $student3 = new Student("Priya", 21, "C");

    echo $student1->get_info();
    echo "<br>";
    echo $student2->get_info();
    echo "<br>";
    echo $student3->get_info();

Output:

Gagan | Age: 20 | Grade: A | GPA: 4
Rahul | Age: 22 | Grade: B | GPA: 3
Priya | Age: 21 | Grade: C | GPA: 2

Now creating a student is clean and compact. One line per student, all data provided upfront. This is exactly how Laravel models work — when Eloquent fetches a record from the database, it creates an object and populates its properties through a constructor-like mechanism.


Access Modifiers — public, protected, private

Access modifiers control who can access a property or method.

public — accessible from anywhere. Inside the class, outside the class, from child classes. This is the default.

private — accessible only from inside the class itself. Nothing outside can read or change it directly.

protected — accessible from inside the class and from child classes (we cover inheritance shortly). Not accessible from outside.


    <?php

    class BankAccount
    {

        public    $owner;
        private   $balance;
        protected $account_number;

        public function __construct($owner, $balance, $account_number)
        {
            $this->owner          = $owner;
            $this->balance        = $balance;
            $this->account_number = $account_number;
        }

        public function deposit($amount)
        {
            if ($amount > 0) {
                $this->balance += $amount;
                echo "Deposited Rs. $amount. New balance: Rs. $this->balance";
            }
        }

        public function withdraw($amount)
        {
            if ($amount > $this->balance) {
                echo "Insufficient balance.";
            } else {
                $this->balance -= $amount;
                echo "Withdrawn Rs. $amount. New balance: Rs. $this->balance";
            }
        }

        public function get_balance()
        {
            return $this->balance;
        }
    }

    $account = new BankAccount("Gagan", 5000, "ACC-001");

    $account->deposit(2000);
    echo "<br>";
    $account->withdraw(1000);
    echo "<br>";
    echo "Balance: Rs. " . $account->get_balance();

    echo "<br>";
    echo $account->owner;

Output:

Deposited Rs. 2000. New balance: Rs. 7000
Withdrawn Rs. 1000. New balance: Rs. 6000
Balance: Rs. 6000
Gagan

If you tried to access $account->balance directly from outside the class, PHP would throw an error — because it is private. The only way to interact with the balance is through the public methods deposit(), withdraw(), and get_balance(). This is called encapsulation — hiding internal details and exposing only what is necessary.

Real world analogy: Your bank account balance is private. You cannot just reach into the bank's database and change your own balance. You can only interact with it through the bank's controlled methods — deposit, withdraw, check balance. That is encapsulation.


Getters and Setters

When a property is private but you still need controlled access to it from outside, you use getter and setter methods.


    <?php

    class Product
    {

        private $name;
        private $price;

        public function __construct($name, $price)
        {
            $this->name  = $name;
            $this->price = $price;
        }

        public function get_name()
        {
            return $this->name;
        }

        public function get_price()
        {
            return $this->price;
        }

        public function set_price($price)
        {
            if ($price < 0) {
                echo "Price cannot be negative.";
                return;
            }
            $this->price = $price;
        }
    }

    $product = new Product("Laptop", 45000);
    echo $product->get_name() . " — Rs. " . $product->get_price();
    echo "<br>";

    $product->set_price(42000);
    echo "Updated price: Rs. " . $product->get_price();
    echo "<br>";

    $product->set_price(-500);

Output:

Laptop — Rs. 45000
Updated price: Rs. 42000
Price cannot be negative.

The setter validates the data before allowing the change. This is the power of encapsulation — the object controls how its own data is modified.


Inheritance — Building on Existing Classes

Inheritance lets one class extend another, inheriting all its properties and methods while adding or overriding its own.

Real world analogy: Think of Animal as a parent class. Dog and Cat are child classes. All animals eat and breathe — those are inherited behaviors. But dogs bark and cats meow — those are behaviors specific to each child class.


    <?php

    class Animal
    {

        public $name;
        public $age;

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

        public function eat()
        {
            echo "$this->name is eating.";
        }

        public function describe()
        {
            echo "I am $this->name and I am $this->age years old.";
        }
    }

    class Dog extends Animal
    {

        public $breed;

        public function __construct($name, $age, $breed)
        {
            parent::__construct($name, $age);
            $this->breed = $breed;
        }

        public function bark()
        {
            echo "$this->name says: Woof!";
        }

        public function describe()
        {
            echo "I am $this->name, a $this->breed, and I am $this->age years old.";
        }
    }

    class Cat extends Animal
    {

        public function meow()
        {
            echo "$this->name says: Meow!";
        }
    }

    $dog = new Dog("Bruno", 3, "Labrador");
    $cat = new Cat("Whiskers", 2);

    $dog->describe();
    echo "<br>";
    $dog->bark();
    echo "<br>";
    $dog->eat();
    echo "<br>";

    $cat->describe();
    echo "<br>";
    $cat->meow();
    echo "<br>";
    $cat->eat();

Output:

I am Bruno, a Labrador, and I am 3 years old.
Bruno says: Woof!
Bruno is eating.
I am Whiskers and I am 2 years old.
Whiskers says: Meow!
Whiskers is eating.

extends makes Dog and Cat inherit everything from Animal. parent::__construct() calls the parent class constructor from inside the child constructor — so we do not have to re-write the $name and $age assignment logic.

Dog overrides the describe() method with its own version that includes the breed. Cat does not override it, so it uses Animal's version. This is called method overriding — a child class can replace any inherited method with its own implementation.

In Laravel: every Controller you write extends the base Controller class. Every Model extends the Model class. You get all of Laravel's built-in functionality for free through inheritance, and you only write the code specific to your feature.


Static Properties and Methods

Sometimes you want a property or method to belong to the class itself — not to any specific object. These are called static members.


    <?php

    class Counter
    {

        private static $count = 0;

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

        public static function get_count()
        {
            return self::$count;
        }
    }

    Counter::increment();
    Counter::increment();
    Counter::increment();

    echo "Total count: " . Counter::get_count();

Output: Total count: 3

Static members are accessed with :: instead of ->. Inside the class, you use self:: instead of $this-> because static members belong to the class, not to an object instance.

Real world use in Laravel: Laravel's DB facade, Route facade, and many helper classes use static methods. When you write Route::get() or DB::table(), you are calling static methods.


A Real World Example — A Simple User Class With Database

Let us connect everything — OOP, PDO, and a real database — into one practical example.

Create User.php (capital U — by convention, class files are named with a capital letter):


    <?php

    require_once "pdo_db.php";

    class User
    {
        private $pdo;

        public $id;
        public $name;
        public $email;
        public $created_at;

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

        public function create($name, $email)
        {
            $stmt = $this->pdo->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
            $stmt->execute([":name" => $name, ":email" => $email]);
            return $this->pdo->lastInsertId();
        }

        public function find($id)
        {
            $stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = :id");
            $stmt->execute([":id" => $id]);
            $data = $stmt->fetch();

            if ($data) {
                $this->id         = $data["id"];
                $this->name       = $data["name"];
                $this->email      = $data["email"];
                $this->created_at = $data["created_at"];
                return true;
            }

            return false;
        }

        public function all()
        {
            $stmt = $this->pdo->query("SELECT * FROM users ORDER BY id DESC");
            return $stmt->fetchAll();
        }

        public function delete($id)
        {
            $stmt = $this->pdo->prepare("DELETE FROM users WHERE id = :id");
            $stmt->execute([":id" => $id]);
            return $stmt->rowCount();
        }

        public function getDisplayName()
        {
            return ucwords(strtolower($this->name));
        }
    }

    $user = new User($pdo);

    $new_id = $user->create("anjali sharma", "anjali@example.com");
    echo "Created user with ID: " . $new_id . "<br>";

    if ($user->find($new_id)) {
        echo "Found: " . $user->getDisplayName() . "" . $user->email . "<br>";
    }

    $all_users = $user->all();
    echo "Total users: " . count($all_users) . "<br>";

    foreach ($all_users as $u) {
        echo $u["id"] . "" . htmlspecialchars($u["name"]) . "<br>";
    }

This User class encapsulates all database operations for the users table. You create one User object and call methods on it. No raw SQL scattered across your files.

Look familiar? This is almost exactly what Laravel's Eloquent Model does. In Laravel you will write:


    <?php

    $user = User::create(["name" => "Gagan", "email" => "gagan@example.com"]);
    $user = User::find(1);
    $users = User::all();

    ?>

That is Eloquent — a much more advanced version of exactly what we just built. Now you understand what is happening underneath.


What Did We Learn in This Post?

A class is a blueprint that bundles related data (properties) and behavior (methods) together. An object is a specific instance created from that blueprint using new.

$this refers to the current object inside a class method. The constructor __construct() runs automatically when an object is created.

public properties and methods are accessible from anywhere. private ones are accessible only inside the class. protected ones are accessible inside the class and its children.

Encapsulation hides internal details and exposes only controlled access points — keeping data safe and code predictable.

Inheritance lets a child class extend a parent class, inheriting all its properties and methods while adding or overriding its own.

Static methods and properties belong to the class itself, not to any object. Accessed with ::.

Laravel is built entirely on OOP — every Controller, Model, and Middleware is a class. Everything you learned in this episode is the direct foundation of everything Laravel does.


What is Coming in Episode 14?

We have one more Core PHP topic before we start Laravel — PHP interfaces and abstract classes, plus a brief look at namespaces and autoloading.

These three concepts are exactly what Laravel uses to organize its massive codebase. Interfaces define contracts. Abstract classes define partial blueprints. Namespaces prevent naming conflicts across hundreds of files. Autoloading loads class files automatically without require_once everywhere.

After Episode 14, we start Laravel. The finish line of Core PHP is one episode away.

See you in the next one.


Next Episode: Interfaces, Abstract Classes, and Namespaces — The Last Core PHP Concepts Before Laravel

This is Episode 13 of the PHP and Laravel — Zero to Hero series.


PHP & Laravel — Zero to Hero Episode 15: Installing Laravel on Windows 11 — Complete Guide

What Are We Doing in This Post? Core PHP is done. Fourteen episodes of solid foundation. Now we install Laravel. But here is the honest trut...