OOP: Polymorphism and More Advanced Topics

Table of Contents

  • Introduction to Polymorphism
    • What is Polymorphism?
    • Types of Polymorphism
    • Implementing Polymorphism in PHP
    • Real-World Example of Polymorphism
  • More Advanced OOP Topics
    • Abstract Classes and Methods
    • Static Methods and Properties
    • Method Overloading
    • Method Overriding
    • Late Static Binding
  • Practical Examples
    • Example 1: Implementing Polymorphism
    • Example 2: Working with Abstract Classes and Methods
  • Summary

Introduction to Polymorphism

Polymorphism is one of the four fundamental principles of Object-Oriented Programming (OOP), alongside encapsulation, inheritance, and abstraction. The term polymorphism comes from the Greek words poly (many) and morph (form), which together mean many forms. In OOP, polymorphism refers to the ability of a class to take on different forms. It allows a single interface to be used for different data types, enabling objects of different classes to be treated as objects of a common superclass.


What is Polymorphism?

In simple terms, polymorphism allows methods to perform different actions based on the object that it is acting upon. With polymorphism, the same method name can behave differently for different objects, making the code more flexible and easier to maintain.


Types of Polymorphism

Polymorphism can be broadly classified into two types:

  1. Compile-time Polymorphism (Method Overloading):
    • This type of polymorphism is resolved at compile time. It occurs when you have multiple methods with the same name, but they differ in the number or types of their parameters.
    • PHP does not natively support method overloading in the same way as other languages like Java, but you can achieve similar behavior using variable-length arguments or magic methods.
  2. Run-time Polymorphism (Method Overriding):
    • This occurs when a subclass provides a specific implementation of a method that is already defined in its superclass.
    • The method in the subclass overrides the one in the superclass, and the specific method executed depends on the type of object instantiated.

Implementing Polymorphism in PHP

In PHP, polymorphism is most commonly implemented via method overriding. Here’s a simple example using two classes, Animal and Dog, to demonstrate run-time polymorphism.

Polymorphism Example: Run-time Polymorphism

<?php
// Parent class
class Animal {
public function makeSound() {
echo "Animal makes a sound\n";
}
}

// Child class
class Dog extends Animal {
public function makeSound() {
echo "Dog barks\n";
}
}

// Child class
class Cat extends Animal {
public function makeSound() {
echo "Cat meows\n";
}
}

// Demonstrating polymorphism
function animalSound(Animal $animal) {
$animal->makeSound();
}

$dog = new Dog();
$cat = new Cat();

animalSound($dog); // Output: Dog barks
animalSound($cat); // Output: Cat meows
?>

In this example:

  • Both the Dog and Cat classes override the makeSound() method of the Animal class.
  • The animalSound() function accepts an Animal object, but it can handle objects of any class that extends Animal (like Dog or Cat).
  • This demonstrates run-time polymorphism, where the correct method (makeSound()) is called based on the actual object type (Dog or Cat).

Real-World Example of Polymorphism

Consider a scenario where you have different types of payment methods in an e-commerce system, such as credit card, PayPal, and Bitcoin. All these classes share a common interface PaymentMethod, but each one implements the processPayment() method in a way specific to that payment method.

<?php
// PaymentMethod Interface
interface PaymentMethod {
public function processPayment($amount);
}

// CreditCard class implementing PaymentMethod
class CreditCard implements PaymentMethod {
public function processPayment($amount) {
echo "Processing credit card payment of $amount\n";
}
}

// PayPal class implementing PaymentMethod
class PayPal implements PaymentMethod {
public function processPayment($amount) {
echo "Processing PayPal payment of $amount\n";
}
}

// Bitcoin class implementing PaymentMethod
class Bitcoin implements PaymentMethod {
public function processPayment($amount) {
echo "Processing Bitcoin payment of $amount\n";
}
}

// Polymorphism in action
function processTransaction(PaymentMethod $paymentMethod, $amount) {
$paymentMethod->processPayment($amount);
}

$creditCard = new CreditCard();
$paypal = new PayPal();
$bitcoin = new Bitcoin();

processTransaction($creditCard, 100); // Output: Processing credit card payment of 100
processTransaction($paypal, 50); // Output: Processing PayPal payment of 50
processTransaction($bitcoin, 200); // Output: Processing Bitcoin payment of 200
?>

Here, the processTransaction() function demonstrates polymorphism. It works with any class that implements the PaymentMethod interface, but the actual processPayment() method executed depends on the class of the object passed to the function.


More Advanced OOP Topics

Now that we’ve covered polymorphism, let’s dive into some other advanced OOP topics that enhance PHP development:


Abstract Classes and Methods

An abstract class is a class that cannot be instantiated on its own. It must be extended by other classes. Abstract classes are used to define common behavior for a group of related classes, while allowing for specific implementations in the derived classes.

<?php
abstract class Shape {
abstract public function calculateArea();
}

class Circle extends Shape {
public function calculateArea() {
return pi() * pow(5, 2); // Radius = 5
}
}

$circle = new Circle();
echo $circle->calculateArea(); // Output: 78.539816339744
?>

In this example, the Shape class is abstract and cannot be instantiated. The Circle class extends it and provides its own implementation for the calculateArea() method.


Static Methods and Properties

Static methods and properties belong to the class itself, rather than instances of the class. They are accessed using the :: operator.

<?php
class Counter {
public static $count = 0;

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

Counter::increment();
echo Counter::$count; // Output: 1
?>

In this example, the static property $count and static method increment() are accessed without creating an instance of the Counter class.


Method Overloading

In PHP, method overloading refers to the ability to dynamically create methods at runtime. This is achieved using the __call() magic method. PHP does not support method overloading natively like some other languages, but you can use the __call() method to handle unknown method calls.

<?php
class DynamicMethods {
public function __call($name, $arguments) {
echo "Calling $name with arguments: " . implode(', ', $arguments) . "\n";
}
}

$object = new DynamicMethods();
$object->testMethod('argument1', 'argument2'); // Output: Calling testMethod with arguments: argument1, argument2
?>

Method Overriding

Method overriding occurs when a subclass provides a specific implementation for a method that is already defined in its parent class. We covered this in the polymorphism section earlier.


Late Static Binding

Late Static Binding (LSB) is a feature introduced in PHP 5.3. It allows you to call static methods from a context other than the class where the method is defined. It uses the static:: keyword instead of self::.

<?php
class ParentClass {
public static function whoAmI() {
echo "I am a " . static::class . "\n";
}
}

class ChildClass extends ParentClass {}

ChildClass::whoAmI(); // Output: I am a ChildClass
?>

Here, static::class in the whoAmI() method resolves to the class that called the method (ChildClass in this case), not the parent class.


Practical Examples

Example 1: Implementing Polymorphism

<?php
class Shape {
public function draw() {
echo "Drawing a generic shape\n";
}
}

class Square extends Shape {
public function draw() {
echo "Drawing a square\n";
}
}

class Circle extends Shape {
public function draw() {
echo "Drawing a circle\n";
}
}

$shapes = [new Shape(), new Square(), new Circle()];

foreach ($shapes as $shape) {
$shape->draw();
}
?>

Output:

Drawing a generic shape
Drawing a square
Drawing a circle

In this example, polymorphism is used to invoke the draw() method on objects of different classes, and each class provides its own implementation.


Summary

In this module, we explored polymorphism and several other advanced OOP topics in PHP. Polymorphism allows methods to behave differently based on the object type, enhancing flexibility and code reusability. We also covered abstract classes, static methods, method overloading, method overriding, and late static binding.

These advanced topics enable developers to write more maintainable, scalable, and flexible PHP applications.