6 - oop in php

Preview
1 min
11 min read

6 - OOP in PHP: Practical guide with real-world business examples

Short description: Learn classes, inheritance, constructors, visibility (public/protected/private), static properties/methods, and how to apply these concepts to real business systems (users, players, customers, CRM).

Why OOP matters for real business apps (SEO: PHP OOP, PHP classes, PHP inheritance)

Object-Oriented Programming (OOP) helps you write clear, maintainable, and reusable code — essential for business apps such as CRMs, e-commerce platforms, learning management systems and SaaS products. Instead of scattered procedural functions, OOP organizes code into objects (users, orders, products) that mirror real business entities. This improves developer collaboration, speeds up feature delivery, and simplifies long-term maintenance.

Lesson goals

  • Understand PHP classes, properties and methods.
  • Learn differences between public, protected, and private.
  • See how static properties and methods work and when to use them.
  • Understand constructors and $this vs self::.
  • Walk through the provided Member and Player example and map it to business scenarios.
  • Follow best practices and avoid common pitfalls.

Provided example — files and code

Two files are used in the example: member.php (a base class) and Player.php (extends Member).

member.php (base class)

<?php
class Member {
    public static $member = "Ali";
    public $memberName = "Ahmed";
    public static $memberSelected = "no";
    // Autoload with the class
    function __construct($age) {
        // this: related to the closest object
        self::$memberSelected = "yes";
        echo $age;
    }
    public static function getMemberPublic() {
        // return $this->member['name'];
        echo "hello from function static <br/>";
        // echo $this->getMemberName();
        // echo $this->member;
    }
    // can't access this function everywhere except the class itself or an extends class
    protected function getMemberName() {
        // return $this->member['name'];
        echo "function getMemberName";
    }
    // private method can be called only within the class
    private function calcAgeInDays() {
        echo "<br/> calc age in days <br/> ";
    }
}

Player.php (child class)

<?php
include_once('member.php');
class Player extends Member {
    public function getPlayerName() {
        // echo $this->getMemberName(); // protected only from another class
        // echo $this->calcAgeInDays(); // error, no call for private
    } 
}
echo Player::$memberSelected;
echo "<br/>";
new Player(32);
echo Player::$memberSelected;

Line-by-line explanation (key concepts)

1. Class and instance properties

public $memberName is an instance property — every object (instance of Member) gets its own copy. Use instance properties for data specific to an individual entity (a particular user, order, or product).

2. Static properties

public static $member and public static $memberSelected belong to the class itself (not to individual objects). They are shared across the entire class and its children. Use static properties for values that are global to a class (feature flags, counters, shared configuration).

3. The constructor __construct($age)

When you create a new Member (or Player, because it inherits the constructor), the constructor runs and receives $age. In the example it sets the static $memberSelected to "yes" and echoes the age. In business code, constructors typically initialize required properties or inject dependencies (database, logger).

4. $this vs self::

$this refers to the current object instance; you use it to access instance properties and methods. self:: refers to the class where the code is written (static context) — use it to access static properties/methods. In the example, the constructor uses self::$memberSelected to modify the static property.

5. Visibility: public, protected, private

  • public — accessible from anywhere (instances, other classes, global scope).
  • protected — accessible inside the class and by child classes (inheritance), but not from outside.
  • private — accessible only inside the class where declared (not even child classes).

In the example, getMemberName() is protected, so Player can call it. calcAgeInDays() is private so it's not available in Player (commented out to show an error if called).

6. Static methods

public static function getMemberPublic() is callable without creating an instance: Member::getMemberPublic(). Static methods are useful for utility functions that don't require object state.

7. Instantiation and static behavior in the example

The example prints Player::$memberSelected before and after creating a new Player(32). Because the constructor sets self::$memberSelected = "yes", the value changes after instantiation — illustrating how static class state can be updated at runtime.

Practical business examples

Example A — CRM: Member and Customer

Map Member to a generic User or Customer class. A Customer class might extend User adding purchase history and loyalty points. Use protected methods for internal calculations (e.g., computing tier level) and private methods for confidential logic (e.g., decrypting a value).

Example B — E-commerce: Product & DigitalProduct

A base Product class has shared fields (price, SKU, name). DigitalProduct extends it (adds download link). Static properties can store global tax rates or SKU prefixes.

Example C — Gaming / LMS: Player & Member (your example)

Your Member / Player example matches a gaming or LMS scenario: Member stores common attributes; Player adds gameplay-specific logic. The constructor could load profile data; protected methods manage private profile workflows; statics can track global settings like "maintenance mode".

Best practices & patterns

  1. Prefer composition to excessive inheritance. Use traits or dependency injection when appropriate.
  2. Minimize use of public properties. Use getters/setters to validate access — or declare properties protected/private and expose controlled accessors.
  3. Limit static state. Static properties are global and can introduce hard-to-track side effects; prefer dependency injection or singletons only when justified.
  4. Keep constructors lightweight. Avoid heavy logic in constructors; prefer factory methods for complex initialization.
  5. Use protected for extensibility. Make helper methods protected if subclasses should reuse them, but keep sensitive logic private.
  6. Document methods and visibility. Use PHPDoc for methods and properties so IDEs and documentation tools help other developers.

Common pitfalls (and how to avoid them)

  • Calling private methods from child classes: will error. Use protected if child classes need access.
  • Overusing static state: leads to hidden dependencies across requests. Use small, controlled static values or dependency injection.
  • Echoing inside models: In the example, the constructor echoes $age. For clean separation, models should not echo or print — controllers or views should handle output.
  • Shadowing properties: Avoid redeclaring same-named properties in child classes unless intentionally overriding (and document it).

Refactored example (cleaner, business-ready)

Below is a cleaner version that avoids echoing inside the class and uses getters:

<?php
class Member {
    protected string $memberName = "Ahmed";
    protected static string $memberSelected = "no";

    public function __construct(protected int $age) {
        self::$memberSelected = "yes";
    }

    public static function isMemberSelected(): bool {
        return self::$memberSelected === "yes";
    }

    protected function getMemberName(): string {
        return $this->memberName;
    }

    private function calcAgeInDays(): int {
        return $this->age * 365;
    }
}

class Player extends Member {
    public function getPlayerName(): string {
        return $this->getMemberName(); // allowed: protected
    }
}

$player = new Player(32);
// presentation layer prints values:
echo $player->getPlayerName();
echo Member::isMemberSelected() ? 'selected' : 'not selected';

Mini exercises (practice)

  1. Modify Member to accept name and age. Add a public method getProfile() that returns an array with name and age.
  2. Create a Coach class that extends Member and adds a method assignPlayer(Player $p).
  3. Replace the static $memberSelected with a dependency-injected FeatureToggle service and show how to instantiate with a factory.

SEO-friendly FAQ (short answers, good for snippets)

What is the difference between public, protected and private in PHP?
Public is accessible from everywhere. Protected is accessible inside the class and by subclasses. Private is accessible only within the declaring class.
When should I use static properties?
Use static for truly class-wide state or constants. For shared services or state that evolves per request, prefer dependency injection to avoid side effects.
Why avoid echoing from a constructor?
Constructors should prepare an object's state. Output belongs in the view/presentation layer; mixing them makes testing and reuse harder.

Conclusion & next steps

This lesson explained core OOP concepts using the Member / Player example. You can immediately apply these ideas to user models, product models, and domain objects in business applications. Next lessons could cover: interfaces & abstract classes, dependency injection, design patterns (Repository, Service, Factory), and unit testing OOP code.

Meta / SEO suggestions

PHP & OOP & MySQLi & PDO

PHP & OOP & MySQLi & PDO

php website
softwarePHPWeb Development Basics
View course

Course Lessons