Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 19

Abstract Classes and Methods: Creation and Extension

Recommended resources

Hello! Welcome back to our module on Advanced OOP Concepts.

In the last lesson, we explored interfaces and saw how they act as pure contracts, defining a "can-do" relationship that enables polymorphism. We learned that an interface specifies what a class must do, but not how.

Today, we'll dive into abstract classes, a powerful feature that blends the concepts of inheritance and contracts. An abstract class serves as a template that other classes can extend. It can provide shared, ready-to-use code (like a normal parent class) while also defining abstract methods that child classes are required to implement (like an interface).

This lesson will teach you how to create and extend abstract classes to build more organized, reusable, and maintainable code—a key practice in professional web development.

1. What are Abstract Classes and Methods?

An abstract class is a special type of class that cannot be instantiated on its own. It's meant to be a base or a blueprint for other, more specific "concrete" classes. Think of it as an incomplete template that provides some common structure and functionality, but leaves certain specific parts for its children to fill in.

The parts that must be filled in are called abstract methods. These are method declarations without any implementation (no code block).

Let's start with a video that clearly explains these fundamental concepts.

14: Abstract Classes in OOP PHP | Abstract Explained | Object Oriented PHP Tutorial | PHP Tutorial

This video from the Dani Krossing channel introduces abstract classes and methods, explaining their purpose and the rules that govern them.

Watch the specified clips to understand the core principles: Declaring an Abstract Class (04:42 - 06:46): Pay attention to the abstract keyword and the key rule that you cannot create an object directly from an abstract class. Creating an Abstract Method (06:46 - 09:30): Observe how an abstract method is declared (with no body) and how it forces any child class to provide an implementation for it. Notice the similarity to an interface's contract.

To summarize the key rules you just saw:

  1. A class is declared abstract using the abstract keyword: abstract class MyClass { ... }.
  2. You cannot create an instance of an abstract class: new MyAbstractClass(); will result in a fatal error.
  3. An abstract class can contain fully implemented methods and properties, just like a regular class.
  4. It can also contain abstract methods, which are declared with the abstract keyword but have no implementation (e.g., abstract public function doSomething();).
  5. If a class contains even one abstract method, the class itself must be declared abstract.
  6. Any class that extends an abstract class must provide an implementation for all the abstract methods from its parent. Failure to do so will cause a fatal error.

For an authoritative reference, it's always good to consult the official PHP documentation.

PHP Manual: Class Abstraction

The PHP Manual provides a concise and accurate definition of class abstraction. Reading this will solidify the formal rules.

Read the main introductory section of the page, which starts with 'PHP has abstract classes...' and ends just before 'Example #1'. This will reinforce the rules we've just discussed.

This image provides a simple, clear example of the structure in action.

PHP Abstract Class and Method Example
This example shows an abstract `Car` class with an abstract `intro()` method. The concrete classes (`Tata`, `Kia`, `MG`) extend `Car` and each provides its own unique implementation of the `intro()` method, demonstrating the combination of shared structure and required specialization.

2. A Practical Use Case: The Base Controller

So, why would you use an abstract class? One of the most common and practical uses in web development is to create a base controller.

In many applications, your controllers will have repetitive code for tasks like rendering a view or handling responses. An abstract base controller allows you to write that common code once and then have all your specific controllers inherit it, keeping your code DRY (Don't Repeat Yourself).

Build a PHP Framework: The Base Controller

This excellent video by Dave Hollingworth demonstrates building a base controller for a PHP framework. It's a perfect real-world example of why abstract classes are so useful for your goal of building full web applications.

Watch from the beginning to 02:44. Focus on how the presenter identifies duplicated code in two different controller classes and then refactors it into a new AbstractController. Notice the problem: Both HomeController and ProductController have nearly identical code for rendering a template. See the solution: An AbstractController is created. The repeated logic is moved into a shared render() method within this abstract class. Observe the result: The concrete controllers now extend the AbstractController and can simply call $this->render(), dramatically simplifying their code.

This pattern is extremely common in professional PHP frameworks. By creating a base class, you establish a common foundation for a whole category of objects (like controllers), sharing functionality while still allowing for specialization.


3. Abstract Classes vs. Interfaces

In the last lesson, we previewed the difference between abstract classes and interfaces. Now that you've seen both in action, let's solidify the distinction. This is a crucial concept for making good design decisions in your projects.

Feature Abstract Class Interface
Relationship is a (e.g., StripeGateway is a PaymentGateway) can do (e.g., FileLogger can do Loggable)
Keyword extends implements
Multiple? No, can only extend one class. Yes, can implement many interfaces.
Implementation Can contain both implemented and abstract methods. Can only contain abstract method signatures.
Properties Can contain properties. Cannot contain properties (only constants).
Purpose Share code among closely related classes. Define a contract for unrelated classes.
Interface Vs Abstract Class (PHP) Comparison
This chart is a useful reference for the key differences. The primary distinction is that abstract classes can provide implementation and define an 'is-a' relationship, while interfaces are pure contracts defining a 'can-do' capability.

A user on the PHP manual page provided a great mental shortcut:

  • class X implements Y says: "X agrees to speak language Y."
  • class X extends Y says: "X is going to complete the partial class Y."

This captures the essence: implements is about agreeing to a communication protocol, while extends is about building upon an existing, incomplete foundation.


4. Hands-on Practice: Payment Gateway

Let's apply these concepts to another common web development scenario: a payment processing system. We'll create a base AbstractPaymentGateway that defines a common structure and some shared logic.

Your Task:

  1. Create the Abstract Class:

    • Define an abstract class named AbstractPaymentGateway.
    • It should have a protected string $apiKey.
    • It needs a public function __construct(string $apiKey) that sets the API key.
    • Add a concrete (fully implemented) public method named generateTransactionID() that returns a unique random string. You can use uniqid() for this. This represents shared logic that all gateways can use.
    • Add an abstract public function charge(float $amount): void. This method's logic will be specific to each payment provider, so we make it abstract.
  2. Create Concrete Implementations:

    • Create a class named StripeGateway that extends AbstractPaymentGateway.
    • Implement the charge() method. For this exercise, it can simply echo a message like: "Charging $$amount using Stripe.".
    • Create another class named PayPalGateway that also extends AbstractPaymentGateway.
    • Implement its charge() method to echo a message like: "Charging $$amount using PayPal.".
  3. Instantiate and Test:

    • Create an instance of StripeGateway, passing it a fake API key (e.g., "stripe_key_123").
    • Call its charge() method with an amount, like 150.00.
    • Call its generateTransactionID() method and echo the result to see that it inherited the concrete method.
    • Do the same for PayPalGateway.
Click to see a possible solution
<?php

// 1. The Abstract Class (Blueprint)
abstract class AbstractPaymentGateway
{
    protected string $apiKey;

    public function __construct(string $apiKey)
    {
        $this->apiKey = $apiKey;
        echo "Initialized gateway with API key: {$this->apiKey}\n";
    }

    // This is a concrete method, shared by all child classes.
    public function generateTransactionID(): string
    {
        return "txn_" . uniqid();
    }

    // This is an abstract method. Child classes MUST implement it.
    abstract public function charge(float $amount): void;
}

// 2. Concrete Implementations
class StripeGateway extends AbstractPaymentGateway
{
    public function charge(float $amount): void
    {
        echo "Charging $$amount using Stripe.\n";
    }
}

class PayPalGateway extends AbstractPaymentGateway
{
    public function charge(float $amount): void
    {
        echo "Charging $$amount using PayPal.\n";
    }
}

// 3. Instantiate and Test

echo "--- Testing Stripe ---\n";
$stripe = new StripeGateway("stripe_key_123");
$stripe->charge(150.00);
$stripeTxnId = $stripe->generateTransactionID();
echo "Stripe Transaction ID: $stripeTxnId\n\n";

echo "--- Testing PayPal ---\n";
$paypal = new PayPalGateway("paypal_key_abc");
$paypal->charge(75.50);
$paypalTxnId = $paypal->generateTransactionID();
echo "PayPal Transaction ID: $paypalTxnId\n";

/* 
// This line would cause a fatal error, because you can't instantiate an abstract class.
// $gateway = new AbstractPaymentGateway("test"); 
*/

?>

Expected Output (Transaction IDs will vary):

--- Testing Stripe ---
Initialized gateway with API key: stripe_key_123
Charging $150 using Stripe.
Stripe Transaction ID: txn_635b3a3b9c6f9

--- Testing PayPal ---
Initialized gateway with API key: paypal_key_abc
Charging $75.5 using PayPal.
PayPal Transaction ID: txn_635b3a3b9c7fa

Conclusion

Excellent work! You have now mastered abstract classes, a vital tool for creating well-structured and scalable object-oriented applications.

Key Takeaways:

  • An abstract class is a blueprint that cannot be instantiated. It's designed to be extended by other classes.
  • It combines concrete methods (providing shared code) and abstract methods (defining a contract).
  • Use the abstract keyword for the class and for methods that must be implemented by children.
  • Use extends to inherit from an abstract class.
  • Abstract classes are ideal for defining an "is-a" relationship where child classes are specializations of a common base and can share functionality (e.g., BaseController, AbstractPaymentGateway).

Preview of the Next Lesson:
As your projects grow, you'll create dozens or even hundreds of classes. What happens if two different libraries you use both have a class named User? This is where namespaces come in. In our next lesson, we will learn how to use namespaces to organize your code into logical groups and prevent these naming conflicts, which is an essential skill for working on any modern, large-scale PHP project.