PHP Object Oriented Programming পর্ব-৭: Static Method, Properties and Late Static Binding

Static Method এবং Property কি ?

static-method-and-properties-in-php

Late Static Binding নিয়ে আমরা একটু পরেই আলোচনা করব, তার আগে চলুন static কি? সেই বিষয়ে আলোচনা করা যাক।

Object ছাড়া সরাসরি class এর Method এবং Property গুলোকে access করার জন্য সেই method এবং property গুলোকে কে static ঘোষণা করতে হয়। আর static ঘোষণা করার জন্য Method এবং Property নামের পূর্বে static কীওয়ার্ড ব্যবহার করতে হবে। static keyword টি কে access modifier ও বলা যায়। চলুন একটা উদাহরণ দিয়ে দেখা যাক:

<?php
class testStatic{
  // static methods and properties are defined with the static keyword.
  //You can add static keyword before or after visibility (Public, Private, Protected)
  public static $count = 0;
  static public $counter=1; 
  
  public static function counter(){
      
      }
  static public function anotherCounter(){
      
      }
}
?>

Zend Certified PHP Engineering (ZCPE) Course

Static Method এবং Property গুলো কিভাবে access বা ব্যবহার করব?

Static Method এবং Property গুলোর ব্যবহার দুইভাবে ভাগ করা যায়।
১. class এর বাহিরে ব্যবহার
২. class এর ভিতরে ব্যবহার

Static Method এবং Property গুলোর class এর বাহিরে ব্যবহার :

Static Method এবং Property গুলোকে class এর বাহির থেকে Object ছাড়া ব্যবহার করতে চাইলে প্রথমে class এর নামের সাথে (::) scope resolution operator দিতে হয় , তারপর static Method অথবা Property এর নাম লিখতে হয় । আরো ভালো ভাবে বুঝার জন্য নিম্নের উদাহরণটি দেখুন :

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

  
  public static function counter(){
      echo "Its Static Counter";
  }
 
}

//Accessing Static Property and Method Outside of the Class
testStatic::$count=5; // Assigning Value to static Property
echo testStatic::$count; // Calling Static Property with Updated Value
echo "<br>";
testStatic::counter(); // Calling Static Method with Updated Value
?>

Note: scope resolution operator এর পর property নাম এর সাথে অবশ্যই $ (dollar sign) দিতে হবে।

Static Method এবং Property গুলোর class এর ভিতরে ব্যবহার :

Static Method এবং Property গুলোকে class এর ভিতরে $this pseudo-variable ছাড়া ব্যবহার করতে চাইলে প্রথমে class এর নাম অথবা self keyword এর সাথে (::) scope resolution operator দিতে হয় , তারপর static Method অথবা Property এর নাম দিতে হয় । আরো ভালো ভাবে বুঝার জন্য নিম্নের উদাহরণটি দেখুন :

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

  
  public static function counter(){
      echo "Its Static Counter: ";
      echo self::$count++,"<br>"; // accessing static Property inside class
  }
 
}
// Calling Static Method Outside Class
testStatic::counter(); 
testStatic::counter();
testStatic::counter();
?>

Result:

static Method Example in PHP

Create Mathematical Operation with static properties and methods

চলুন static methods এবং properties সহ PHP OOP (Object-Oriented Programming) এর একটি বাস্তব উদাহরণ বিবেচনা করা যাক। এই উদাহরণে, আমরা একটি MathUtility ক্লাস তৈরি করব যাতে গাণিতিক ক্রিয়াকলাপ সম্পাদনের জন্য static methods এবং property রয়েছে।

class MathUtility
{
    // Static property to store the total number of calculations
    private static $totalCalculations = 0;

    // Static method to add two numbers
    public static function add($a, $b)
    {
        self::$totalCalculations++; // Increment the total calculations count
        return $a + $b;
    }

    // Static method to subtract two numbers
    public static function subtract($a, $b)
    {
        self::$totalCalculations++; // Increment the total calculations count
        return $a - $b;
    }

    // Static method to get the total number of calculations
    public static function getTotalCalculations()
    {
        return self::$totalCalculations;
    }
}

// Example usage
$result1 = MathUtility::add(5, 3); // Result: 8
$result2 = MathUtility::subtract(10, 4); // Result: 6

// Get the total number of calculations
$totalCalculations = MathUtility::getTotalCalculations();

// Display results
echo "Result 1: $result1<br>";
echo "Result 2: $result2<br>";
echo "Total Calculations: $totalCalculations";

এই উদাহরণে:

  • ১. MathUtility ক্লাসের একটি private static property $totalCalculations সম্পাদিত গণনার total number ট্র্যাক রাখার জন্য রয়েছে।
  • ২. Two static methods, add এবং subtract, mathematical operations (addition এবং subtraction) operations এবং total calculations count বৃদ্ধি করে।
  • ৩. আরেকটি static method, getTotalCalculations, যা total number রিট্রিভ করে।
  • ৪. ক্লাসের বাইরে, আমরা ক্লাসের কোনো instance তৈরি না করেই static methods (add, subtract, getTotalCalculations) কল করার জন্য class name এবং :: (double colon) সিনট্যাক্স ব্যবহার করি।
  • ৫. গণনার ফলাফলগুলি সম্পাদিত গণনার মোট সংখ্যা সহ প্রদর্শিত হয়।

Log Count with Static Properties and Methods

চলুন Static Method এবং Properties ব্যবহার করে আরো একটি উদাহরণ দেখা যাক:

এই class টি messages লগ করা, লগ কাউন্ট ট্র্যাক রাখা এবং লগগুলি বের করার একটি মেথড প্রদানের জন্য দায়িত্বে থাকবে।

class Logger
{
    // Static property to store the logs
    private static $logs = [];

    // Static property to store the total number of logs
    private static $totalLogs = 0;

    // Static method to log a message
    public static function log($message)
    {
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "$timestamp - $message";

        self::$logs[] = $logEntry; // Add the log entry to the logs array
        self::$totalLogs++; // Increment the total logs count
    }

    // Static method to get all logs
    public static function getLogs()
    {
        return self::$logs;
    }

    // Static method to get the total number of logs
    public static function getTotalLogs()
    {
        return self::$totalLogs;
    }
}

// Example usage
Logger::log("User logged in.");
Logger::log("Error: Database connection failed.");
Logger::log("New product added.");

// Get all logs and total log count
$allLogs = Logger::getLogs();
$totalLogs = Logger::getTotalLogs();

// Display logs and total log count
echo "All Logs:<br>";
foreach ($allLogs as $log) {
    echo "- $log<br>";
}

echo "<br>Total Logs: $totalLogs";

Create Secure User Management System with static property and methods

ইউজারের ডেটা, authentication এবং রেজিস্টার্ড ইউজার সংখ্যা গণনা করার জন্য static methods এবং Static Properties দিয়ে আরো একটি উদাহরণ দেখা যাক :

class User
{
    // Static property to store user data
    private static $users = [];

    // Static property to store the total number of registered users
    private static $totalUsers = 0;

    // Static method to register a new user
    public static function register($username, $email, $password)
    {
        // Validate username, email, and password
        if (!self::isValidUsername($username) || !self::isValidEmail($email) || !self::isValidPassword($password)) {
            return false; // Registration failed due to invalid data
        }

        // Hash the password before storing it
        $hashedPassword = password_hash($password, PASSWORD_DEFAULT);

        // Add the new user to the users array
        self::$users[$username] = [
            'username' => $username,
            'email' => $email,
            'hashedPassword' => $hashedPassword,
        ];

        // Increment the total users count
        self::$totalUsers++;

        return true; // Registration successful
    }

    // Static method to authenticate a user
    public static function authenticate($username, $password)
    {
        // Check if the user exists
        if (isset(self::$users[$username])) {
            $hashedPassword = self::$users[$username]['hashedPassword'];
            
            // Verify the password
            if (password_verify($password, $hashedPassword)) {
                return true; // Authentication successful
            }
        }

        return false; // Authentication failed
    }

    // Static method to get the total number of registered users
    public static function getTotalUsers()
    {
        return self::$totalUsers;
    }

    // Static method for username validation
    private static function isValidUsername($username)
    {
        // Add validation rules for the username (e.g., minimum length)
        return strlen($username) >= 4;
    }

    // Static method for email validation
    private static function isValidEmail($email)
    {
        // Use PHP's built-in email validation for simplicity
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    // Static method for password validation
    private static function isValidPassword($password)
    {
        // Add validation rules for the password (e.g., minimum length)
        return strlen($password) >= 8;
    }
}

// Example usage
if (User::register('john_doe', 'john@example.com', 'password123')) {
    echo "Registration successful!<br>";
} else {
    echo "Registration failed. Invalid data!<br>";
}

if (User::authenticate('john_doe', 'password123')) {
    echo "Authentication successful!<br>";
} else {
    echo "Authentication failed. Invalid credentials!<br>";
}

// Get the total number of registered users
$totalUsers = User::getTotalUsers();

// Display total users count
echo "Total Registered Users: $totalUsers";

Late Static Binding কি ?

PHP তে Static Method এবং Property গুলোকে class এর ভিতরে কল করার জন্য $this pseudo-variable এর পরিবর্তে class এর নাম অথবা “self” keyword এর সাথে (::) scope resolution operator দিয়ে ব্যবহার করা হয় , তখন যেই class এ “self” keyword ব্যবহার করা হয়েছে, “self” keyword শুধু ঐ ক্লাসকেই নির্দিষ্ট করে নেয়। আর তাতে Parent Class এর static Method এবং Property গুলোকে child class এ inherit হয়না। আর সেই জন্য PHP 5.3 থেকে Parent Class এর Static Method এবং Property গুলোকে কে child class এ inherit করার জন্য static Method এবং Property কল করার সময় “self” keyword এর পরিবর্তে “static” keyword ব্যবহার প্রয়োগ করা হয়েছে, আর এটাকেই PHP 5.3 থেকে Late Static Binding বলা হয়। আরো ভালো ভাবে বুঝার জন্য নিম্নের উদাহরণ দুটি দেখুন :

উদাহরণ: “self” keyword এর ব্যবহার

<?php
class Course{
	protected static $courseName = 'Professional PHP';
	public static function getCourseName(){
		return self::$courseName;
	}
}
 
class Student extends Course{
	protected static $courseName = 'Laravel';	
}
 
echo Student::getCourseName(); // Professional PHP, not Laravel

ব্যাখ্যা:

  • প্রথমত, আমরা Course নামক একটি Class তৈরী করি যার মধ্যে আছে $courseName নামে একটি static property যার Value হচ্ছে “PHP Professional” এবং getCourseName নামে একটি static Method তৈরী করি যা $courseName Property এর value return করবে। লক্ষ্য করবেন, যে আমরা Course Class এর ভিতরে static property তে access করার জন্য self এবং “::” scope resolution Operator ব্যবহার করেছি।
  • দ্বিতীয়ত , আমরা Student নামে Course class থেকে একটি child class তৈরী করি, এবং Student class এর মধ্যেও $courseName নামে একটি static property আছে যার value হচ্ছে “Laravel” .
  • তৃতীয়ত , আমরা আমাদের Student child class দিয়ে Course class থেকে getCourseName method কল করি। যাতে আমরা আমাদের Student Child Class এর course name হিসেবে “laravel” পাই। যাই হোক Course class এর getCourseName Method টি আমাদের কে ফলাফল হিসেবে “Laravel” এর পরিবর্তে “PHP Professional” রিটার্ন করে, এর কারণ হচ্ছে self keyword যেই class এ কল করা হয় সেই class ছাড়া child বা অন্য কোনো class কে নির্দিষ্ট করেনা।

উপরের সমস্যা কে সমাধান করার জন্য PHP 5.3 থেকে Late Static Binding সুবিধা যোগ করে। মূলত, self keyword এর পরিবর্তে static keyword টি ব্যবহার করা হয়েছে, যেন যেই class থেকে call করা হবে যেন সেই class কে নির্দিষ্ট করে। চলুন উপরে আমাদের উদাহরণ পরিবর্তন করা যাক:

উদাহরণ: “static” keyword বা Late Static Binding এর ব্যবহার

<?php
class Course{
	protected static $courseName = 'Professional PHP';
	public static function getCourseName(){
		return static::$courseName;
	}
}
 
class Student extends Course{
	protected static $courseName = 'Laravel';	
}
 
echo Student::getCourseName(); // Laravel

এখন আমরা আমাদের প্রত্যাশিত ফলাফল পাব।

Create a Employee Management System with Late Static Binding Feature

আসুন পিএইচপি-তে late static binding ব্যবহার করে একটি বাস্তব-বিশ্বের উদাহরণ তৈরি করি। এই উদাহরণে, আমরা একটি কোম্পানিতে বিভিন্ন ধরনের কর্মচারীদের পরিচালনার জন্য একটি simple framework তৈরি করব। আমরা একটি generic Employee class বাস্তবায়ন করতে late static binding ব্যবহার করব এবং তারপর ম্যানেজার এবং ডেভেলপারের মতো নির্দিষ্ট এমপ্লয়ীদের টাইপ গুলো তৈরি করব।

class Employee
{
    protected static $employeeCount = 0;
    protected $name;
    protected $salary;

    public function __construct($name, $salary)
    {
        $this->name = $name;
        $this->salary = $salary;
        static::$employeeCount++;
    }

    public static function getEmployeeCount()
    {
        return static::$employeeCount;
    }

    public function getDetails()
    {
        return "Name: {$this->name}, Salary: {$this->salary}";
    }
}

class Manager extends Employee
{
    protected static $managerCount = 0;
    protected $department;

    public function __construct($name, $salary, $department)
    {
        parent::__construct($name, $salary);
        $this->department = $department;
        static::$managerCount++;
    }

    public static function getManagerCount()
    {
        return static::$managerCount;
    }

    public function getDetails()
    {
        $parentDetails = parent::getDetails();
        return "$parentDetails, Department: {$this->department}";
    }
}

class Developer extends Employee
{
    protected static $developerCount = 0;
    protected $programmingLanguage;

    public function __construct($name, $salary, $programmingLanguage)
    {
        parent::__construct($name, $salary);
        $this->programmingLanguage = $programmingLanguage;
        static::$developerCount++;
    }

    public static function getDeveloperCount()
    {
        return static::$developerCount;
    }

    public function getDetails()
    {
        $parentDetails = parent::getDetails();
        return "$parentDetails, Programming Language: {$this->programmingLanguage}";
    }
}

// Example usage
$manager1 = new Manager('John Doe', 60000, 'Human Resources');
$developer1 = new Developer('Alice Smith', 50000, 'PHP');
$developer2 = new Developer('Bob Johnson', 55000, 'JavaScript');

// Get total counts for all employees, managers, and developers
$totalEmployees = Employee::getEmployeeCount();
$totalManagers = Manager::getManagerCount();
$totalDevelopers = Developer::getDeveloperCount();

// Display employee details and counts
echo "Employee Details:<br>";
echo $manager1->getDetails() . "<br>";
echo $developer1->getDetails() . "<br>";
echo $developer2->getDetails() . "<br>";

echo "<br>Total Employees: $totalEmployees<br>";
echo "Total Managers: $totalManagers<br>";
echo "Total Developers: $totalDevelopers";

Create Content Management Sytem with Late Static Binding

আসুন একটি content management system (CMS) আরও বিস্তৃত উদাহরণ বিবেচনা করা যাক যেখানে articles, videos এবং images এর মতো বিভিন্ন ধরনের কনটেন্ট এলিমেন্ট গুলি পরিচালনা করতে late static binding ব্যবহার করা হয়। প্রতিটি কনটেন্ট টাইপের নির্দিষ্ট আচরণের সাথে নিজস্ব ক্লাস থাকবে, এবং একটি factory class, late static binding ব্যবহার করে কনটেন্ট টাইপের উপর ভিত্তি করে ডায়নামিক্যাললি instances তৈরি করবে।

abstract class Content
{
    protected $title;
    protected $url;

    public function __construct($title, $url)
    {
        $this->title = $title;
        $this->url = $url;
    }

    abstract public function render();
}

class Article extends Content
{
    public function render()
    {
        return "Rendering Article: {$this->title}";
    }
}

class Video extends Content
{
    public function render()
    {
        return "Rendering Video: {$this->title}";
    }
}

class Image extends Content
{
    public function render()
    {
        return "Rendering Image: {$this->title}";
    }
}

class ContentFactory
{
    public static function createContent($type, $title, $url)
    {
        $className = ucfirst($type);
        if (class_exists($className)) {
            return new $className($title, $url);
        } else {
            throw new Exception("Invalid content type: $type");
        }
    }
}

// Example usage
try {
    $article = ContentFactory::createContent('article', 'PHP Best Practices', '/articles/php-best-practices');
    $video = ContentFactory::createContent('video', 'Introduction to OOP', '/videos/oop-introduction');
    $image = ContentFactory::createContent('image', 'Sunset Landscape', '/images/sunset-landscape');

    echo $article->render() . "<br>";
    echo $video->render() . "<br>";
    echo $image->render() . "<br>";
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}

এই উদাহরণটি ব্যাখ্যা করে যে কিভাবে late static binding একটি content management system এ ব্যবহার করা যেতে পারে তাদের নিজস্ব আচরণের সাথে বিভিন্ন কন্টেন্টের ধরন পরিচালনা করার জন্য যখন dynamic creation এবং রেন্ডারিংয়ের এর সুযোগ দেয়।

PDO-Enhanced Database Model with Late Static Binding

এখানে আমরা একটি ডাটাবেস সংযোগ স্থাপনের জন্য একটি DatabaseConnection ক্লাস তৈরি করব, এবং DatabaseModel ক্লাস CRUD (Create, Read, Update, Delete) অপারেশনের জন্য এই সংযোগটি ব্যবহার করবে। এই উদাহরণটি বুঝার জন্য নিম্নোক্ত Database table দুটি তৈরি করে নিন :

-- Table structure for users
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL
);

-- Table structure for products
CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    price DECIMAL(10, 2) NOT NULL
);

এবার আমরা ক্লাস গুলো তৈরি করব :

class DatabaseConnection
{
    private static $connection;

    public static function getConnection()
    {
        if (!isset(self::$connection)) {
            $host = 'your_database_host';
            $dbname = 'your_database_name';
            $username = 'your_database_username';
            $password = 'your_database_password';

            try {
                self::$connection = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
                self::$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            } catch (PDOException $e) {
                die("Connection failed: " . $e->getMessage());
            }
        }

        return self::$connection;
    }
}

class DatabaseModel
{
    protected static $table;
    protected $data;

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

    public function save()
    {
        $columns = implode(', ', array_keys($this->data));
        $values = implode(', ', array_fill(0, count($this->data), '?'));

        $query = "INSERT INTO {$this::$table} ($columns) VALUES ($values)";
        $stmt = DatabaseConnection::getConnection()->prepare($query);
        $stmt->execute(array_values($this->data));

        echo "Saved data to the '{$this::$table}' table.<br>";
    }

    public static function find($id)
    {
        $query = "SELECT * FROM {$this::$table} WHERE id = ?";
        $stmt = DatabaseConnection::getConnection()->prepare($query);
        $stmt->execute([$id]);

        $data = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($data) {
            echo "Fetched data from the '{$this::$table}' table for ID $id.<br>";
            return new static($data);
        } else {
            echo "No data found for ID $id in the '{$this::$table}' table.<br>";
            return null;
        }
    }
}

class User extends DatabaseModel
{
    protected static $table = 'users';
}

class Product extends DatabaseModel
{
    protected static $table = 'products';
}

// Example usage
$user = new User(['name' => 'John Doe', 'email' => 'john@example.com']);
$user->save();

$product = new Product(['name' => 'Laptop', 'price' => 999]);
$product->save();

$retrievedUser = User::find(1);
$retrievedProduct = Product::find(101);

এই উদাহরণটি দেখায় যে কিভাবে late static binding একটি flexible এবং extensible database model system তৈরি করতে ব্যবহার করা যেতে পারে, বিভিন্ন মডেলগুলিকে প্রতিটি মডেলের জন্য টেবিলের নাম এবং নির্দিষ্ট আচরণগুলি কাস্টমাইজ করার সময় common database interaction method গুলি ভাগ করার অনুমতি দেয়।

আমি মাসুদ আলম, বাংলাদেশের ৩৬ তম Zend Certified Engineer । ২০০৯ সালে কম্পিউটার সাইন্স থেকে বেচেলর ডিগ্রী অর্জন করি। দীর্ঘ ১৫ বছর আমি Winux Soft, SSL Wireless, IBCS-PRIMAX, Max Group, Canadian International Development Agency (CIDA), Care Bangladesh, World Vision, Hellen Keller, Amarbebsha Ltd সহ বিভিন্ন দেশি বিদেশী কোম্পানিতে ডেটা সাইন্স, মেশিন লার্নিং, বিগ ডেটা, ওয়েব ডেভেলপমেন্ট এবং সফটওয়্যার ডেভেলপমেন্ট এর উপর বিভিন্ন লিডিং পজিশন এ চাকরি এবং প্রজেক্ট লিড করি। এছাড়াও বাংলাদেশের ১৮৫ জন জেন্ড সার্টিফাইড ইঞ্জিনিয়ার এর মধ্যে ১২০ এরও অধিক ছাত্র আমার হাতে জেন্ড সার্টিফাইড ইঞ্জিনিয়ার হয়েছেন। বর্তমানে w3programmers ট্রেনিং ইনস্টিটিউট এ PHP এর উপর Professional এবং Advance Zend Certified PHP -8.2 Engineering, Laravel Mastering Course with ReactJS, Python Beginning To Advance with Blockchain, Machine Learning and Data Science, Professional WordPress Plugin Development Beginning to Advance কোর্স করাই। আর অবসর সময়ে w3programmers.com এ ওয়েব টেকনোলজি নিয়ে লেখালেখি করি।

One thought on “PHP Object Oriented Programming পর্ব-৭: Static Method, Properties and Late Static Binding

Leave a Reply