PHP OOP Part-4: Static property, method and this vs self
প্রথমে আমরা property এবং method সম্পর্কে জানার চেষ্টা করব। আমরা যখন একটি ক্লাসের সাহায্যে একাধিক অবজেক্ট ক্রিয়েট করি তখন প্রতিটা অবজেক্ট আলাদা আলাদা Memory location এ allocate হয়। এর ফলে এই অবজেক্টের সব প্রপার্টি এবং মেথডও এই অবজেক্টের এর সাথে মেমোরি location এ allocate থাকে। এর ফলে যখন আমরা কোন অবজেক্টের কোন প্রপার্টিকে চেঞ্জ করি তখন সেই চেঞ্জটা শুধুমাত্র এই অবজেক্টের মধ্যেই সীমাবদ্ধ থাকে। এর প্রভাব অন্য কোন অবজেক্টের উপর পরে না। কারণ কোন একটি ক্লাসের প্রপার্টি বা মেথডগুলো সে ক্লাসের অবজেক্টের সাথে রিলেটেড। এর ফলে এই প্রপার্টি বা মেথড গুলোকে যদি আমরা বাহির থেকে অ্যাক্সেস করতে চাই তাহলে সে ক্লাসের অবজেক্ট ক্রিয়েট করতে হবে আর যদি এই ক্লাসের ভিতরে আমরা এই প্রপার্টি বা মেথড গুলো কে অ্যাক্সেস করতে চাই তাহলে আমরা তাদেরকে $this keyword এর সাহায্যে অ্যাক্সেস করতে পারব। এক্ষেত্রে $this keyword কিন্তু সেই অবজেক্টকেই রিপ্রেজেন্ট করে। আমরা পরবর্তীতে $this keyword সম্পর্কে জানার চেষ্টা করব।
নিচের উদাহারণ টি লক্ষ করা যাক।
class Car
{
public $name;
public $color;
function __construct(string $name, string $color)
{
$this->name = $name;
$this->color = $color;
}
public function getValue()
{
echo "Car name: $this->name\n";
echo "Car color: $this->color\n";
}
}
$tesla = new Car('Zip', 'Blue');
$tesla->getValue();
এই উদাহরণে আমরা দেখতে পাচ্ছি যে এই ক্লাসের প্রোপার্টিগুলোকে এক্সেস করার জন্য একই ক্লাসের মেথডের মধ্যে আমরা $this keyword সাহায্যে এদেরকে ব্যবহার করেছি। আবার এখান থেকে কোনো মেথডকে এই ক্লাসের বাহির থেকে ব্যবহার করার জন্য আমরা এই ক্লাসের একটি অবজেক্ট ক্রিয়েট করেছি। আর এভাবেই মূলত আমরা একটি ক্লাসের নরমাল প্রোপার্টি বা মেথড গুলোকে ব্যবহার করে থাকি।
কিন্তু Static প্রপার্টি বা মেথড গুলি ঠিক এরকম নয়। যখন আমরা কোন ক্লাস ডিফাইন করি তখন সেই ক্লাস মেমোরি লোকেশনে একবারই allocate হবে। আর যখন আমরা কোন ক্লাসের Static প্রপার্টি বা মেথড ডিফাইন করবো তখন সেই Static প্রপার্টি বা মেথডগুলো সেই class এর সাথেই মেমোরির কোনো একটা নির্দিষ্ট লোকেশন এ একবারই allocate হবে।এর ফলে পরবর্তীতে যখনই আমরা এই Static প্রপার্টি বা মেথড গুলোকে পরিবর্তন করব তখন সমস্ত ক্লাসের মধ্যে সেই পরিবর্তনের প্রভাব পড়বে অর্থাৎ যত জায়গায় এই Static প্রপার্টি বা মেথডকে ইউজ করা হয়েছে সবগুলো জায়গাতেই এর ভ্যালুটা পরিবর্তিত হয়ে যাবে। এখন যদি আমরা ক্লাসের Static প্রপার্টি বা মেথড গুলোকে ক্লাসের বাইরে অ্যাক্সেস করতে চাই সেক্ষেত্রে (::) scope resolution অপারেটরের সাহায্যে কোন প্রকার অবজেক্ট ক্রিয়েট করা ছাড়াই ব্যবহার করতে পারব অথবা অবজেক্ট ক্রিয়েট করেও ব্যবহার করতে পারব। আর যদি ক্লাসের ভিতরে এক্সেস করতে চাই সেক্ষেত্রে self keyword বা সেই class name এর সাহায্যে আমরা এগুলোকে এক্সেস করতে পারব। এক্ষেত্রে self keyword কিন্তু সেই ক্লাসকেই রিপ্রেজেন্ট করে। আমরা পরবর্তীতে self keyword সম্পর্কে জানার চেষ্টা করব।
নিচের উদাহারণ টি লক্ষ করা যাক।
class Car
{
public static $name;
public static $color;
function __construct($name, $color)
{
self::$name = $name;
self::$color = $color;
}
public static function getValue()
{
echo "Car name: " . self::$name . "\n";
echo "Car color: " . self::$color . "\n";
}
}
$toyota = new Car('Toyota', 'Black');
$bmw = new Car('BMW', 'Orange');
$toyota::getValue();
$bmw::getValue();
Car::getValue();
এই উদাহরণে আমরা দেখতে পাচ্ছি যে এই ক্লাসের প্রোপার্টিগুলোকে এক্সেস করার জন্য একই ক্লাসের মেথরের মধ্যে আমরা self keyword সাহায্যে এদেরকে ব্যবহার করেছি। আবার এখান থেকে কোনো একটি Static মেথডকে এই ক্লাসের বাহির থেকে ব্যবহার করার জন্য আমরা এই ক্লাসের একটি অবজেক্ট ক্রিয়েট করেছি আবার অবজেক্ট ক্রিয়েট করা ছাড়াও সরাসরি Class এর নামের মাধ্যমে (::) scope resolution অপারেটরের সাহায্যে ব্যবহার করেছি। আর এভাবেই মূলত আমরা একটি ক্লাসের Static প্রোপার্টি বা মেথড গুলোকে ব্যবহার করে থাকি।
এখন উপরের উদাহারণ এ দেখতে পাচ্ছি যে Car ক্লাসের সাহায্যে ভিন্ন ভিন্ন ডাটা দিয়ে আমরা $toyota এবং $bmw নামে দুটো অবজেক্ট তৈরি করেছি। এখন এই অবজেক্ট দুটির value আমরা এক্সেস করতে চাচ্ছি। এখন যদি আমরা উপরের কোড রান করি তাহলে নিচের আউটপুট দেখতে পাবো।
Car name: BMW
Car color: Orange
Car name: BMW
Car color: Orange
Car name: BMW
Car color: Orange
আমরা দেখতে পাচ্ছি যে ওই দুটি অবজেক্টের ভ্যালুই same আসতেছে অর্থাৎ সর্বশেষ যে অবজেক্ট ক্রিয়েট করেছি সেই অবজেক্টের ভ্যালুগুলোই মূলত আমরা এদের value হিসেবে পেয়ে যাচ্ছি। শুধু তাই নয় সরাসরি ক্লাসের মাধ্যমে আমরা যখন ভেলু access করতে চাচ্ছি ঠিক তখনও same ভ্যালু অর্থাৎ second class এর ভ্যালু গুলোই আমরা পাচ্ছি।
আর এর কারণটা অবশ্যই বুঝতে পারছেন কারণ আমরা শুরুতেই বলেছিলাম যে Static প্রপার্টি বা মেথড গুলি মেমোরির কোন একটি লোকেশনে একবার ক্রিয়েট হয় পরবর্তীতে যখন কোন একটা জায়গা থেকে সেই Static প্রপার্টি বা মেথড গুলো চেঞ্জ করা হয় সেই চেঞ্জ এর effect সব অবজেক্টে এর উপর পরে। তাই উপরের উদাহরণে যখন আমরা দ্বিতীয়বার আরেকটি অবজেক্ট ক্রিয়েট করি তখন সেই অবজেক্ট ক্রিয়েট হওয়ার সাথে সাথে প্রপার্টিগুলোর ভ্যালু চেঞ্জ হয়ে যায়। যার ফলে এই চেঞ্জ এর ইফেক্ট তার আগের অবজেক্ট এর উপরেও পড়েছে।
এখানে মনে রাখতে হবে যে ক্লাসের স্টেটিক প্রপার্টি বা মেথড গুলোকে ব্যবহার করতে হলে নরমাল ক্লাসের প্রপার্টি বা মেথডের মত করে আমরা → চিহ্ন দিয়ে ব্যবহার করতে পারব না এক্ষেত্রে অবশ্যই (::) scope resolution অপারেটরের সাহায্যে এদেরকে ব্যবহার করতে হবে সেটা হোক ক্লাসের ভিতরে অথবা বাহিরে।
$this vs self keyword
$this keyword কি?
ইতোমধ্যে আমরা $this এবং self keyword এর ব্যবহার দেখেছি। এখন আমরা এই $this এবং self keyword সম্পর্কে আরেকটু বিস্তারিত জানার চেষ্টা করব।
$this হল পিএইচপির একটি build int keyword । আমরা কোন একটি ক্লাসের সাহায্যে এক বা একাধিক অবজেট ক্রিয়েট করতে পারি। এখন সেই ক্লাসের মধ্যে যে সকল Normal প্রপার্টি বা মেথডগুলো রয়েছে এগুলোকে আমরা ওই ক্লাসের মধ্যে যদি access করতে চাই তাহলে সেগুলোকে আমরা $this এর সাহায্য access করতে পারব। এখন আমরা জানি যে যখন আমরা কোন একটি ক্লাস ডিফাইন করি তখন সেই ক্লাস মেমোরির কোন একটি লোকেশনে একবারই এলোকেট হয়। তাহলে এখন প্রশ্ন হতে পারে যদি আমরা এ ক্লাসের সাহায্যে একাধিক অবজেক্ট তৈরি করি তাহলে $this কিওয়ার্ড কি সবগুলো অবজেক্টের জন্য একবারই এই প্রপার্টি বা মেথডকে access করবে?
এর উত্তর হল “না”। কারণ আমরা ইতোমধ্যে কিছুটা ধারণা লাভ করেছি যে $this keyword ক্লাসকে রিপ্রেজেন্ট করে না বরং সেই ক্লাসের দ্বারা যে অবজেক্ট ক্রিয়েট করা হয় তাকেই মূলত রিপ্রেজেন্ট করে। অর্থাৎ আমরা বুঝতে পারলাম যে $this keyword সরাসরি অবজেক্টের সাথে রিলেটেড। এর ফলে আমরা যতগুলো অবজেক্ট ক্রিয়েট করব সবগুলো অবজেক্টের জন্য আলাদা আলাদা ভাবে এই $this keyword সেই ক্লাসের মধ্যে থাকা প্রপার্টি বা মেথড গুলোকে এক্সেস করবে।
নিচের উদাহারণ টি লক্ষ করা যাক।
class Car
{
public $name;
public $color;
function __construct($name, $color)
{
$this->name = $name;
$this->color = $color;
}
public function getValue()
{
echo "Car name: " . $this->name . "\n";
echo "Car color: " . $this->color . "\n";
}
}
উপরের উদাহরণটা আমরা অনেকবার ব্যবহার করেছি কিন্তু এখানে $this ব্যবহার নিয়ে তেমন আলোচনা করা হয়নি। কিন্তু এখন যেহেতু আমরা $this সম্পর্কে কিছুটা ধারণা লাভ করেছি তাই $this এর ব্যবহার আমরা আরও ভালো ভাবে বুঝতে পারব। আবার এই ক্লাসের সাহায্যে আমরা Object Create করেছি। এখন আমরা বুঝতে পারতেছি যে এই $this কিওয়ার্ড প্রতিটা অবজেক্টের জন্য আলাদা আলাদা ভাবে প্রপার্টিগুলোকে এক্সেস করতেছে।
কিন্তু এখানে মনে রাখতে হবে যে $this keyword কে আমরা কোন স্ট্যাটিক মেথড এর মধ্যে ব্যবহার করতে পারব না। কেন ব্যবহার করতে পারব না সেটা আমরা একটু পরেই বুঝতে পারব।
self keyword কি?
আমরা ইতিমধ্যে জেনেছি যে যখন আমরা কোন ক্লাস ডিফাইন করি তখন সে ক্লাসটি মেমোরি লোকেশনে একবার allocate হয় এবং সেই ক্লাসের মধ্যে যতগুলো স্ট্যাটিক প্রপার্টি এবং মেথড থাকে সেই স্ট্যাটিক প্রপার্টি বা মেথডগুলোও সেই ক্লাসের সাথে মেমরি লোকেশনে একবারে allocate হয়। এর ফলে আমরা যতবারই এই ক্লাসের সাহায্যে অবজেক্ট ক্রিয়েট করব সেই অবজেক্ট ক্রিয়েট করার ফলে এই ক্লাসের মধ্যে থাকা স্ট্যাটিক প্রপার্টি বা মেসেজগুলো প্রতিটা অবজেক্টের জন্য আলাদা আলাদা create হবে না। তাই এই ক্লাসের মধ্যে আমরা এদেরকে $this keyword দিয়ে access করতে পারবো না। কারণ আমরা ইতিমধ্যে জানি যে $this মূলত সেই ক্লাসের অবজেক্টকে রিপ্রেজেন্ট করে। কিন্তু এখানে স্ট্যাটিক প্রপার্টি বা মেথডগুলো তো অবজেক্টের সাথে রিলেটেড না বরং এগুলো সরাসরি সেই ক্লাসের সাথে রিলেটেড। তাই এদেরকে আমরা এই ক্লাসের মধ্যে এক্সেস করতে হলে self keyword দিয়ে অথবা সে ক্লাসের নাম দিয়ে (::) scope resolution অপারেটরের সাহায্যে আমরা এদেরকে অ্যাক্সেস করতে পারবো। কারন আমরা জানি self keyword ক্লাসকে রিপ্রেজেন্ট করে।
নিচের উদাহারণ টি লক্ষ করা যাক।
class Car
{
public $name;
public static $color = "Red";
function __construct($name)
{
$this->name = $name;
}
public function getValue()
{
echo "Car name: " . $this->name . "\n";
echo "Car color: " . self::$color . "\n";
}
public static function getStaticValue()
{
$obj = new self("Toyota");
echo "Car name: " . $obj->name . "\n";
echo "Car color: " . self::$color . "\n";
}
}
এই উদাহরণে আমরা দেখতে পাচ্ছি যে নন স্ট্যাটিক method এর মধ্যে স্ট্যাটিক মেম্বার গুলোকে খুব সহজেই সেই ক্লাসের নাম ধরে অথবা সেলফ কিওয়ার্ড দিয়ে (::) scope resolution অপারেটরের সাহায্যে আমরা এদেরকে অ্যাক্সেস করতে পারছি কারন এরা ক্লাসের সাথে রিলেটেড। তাই এদেরকে access করতে হলে আলাদা করে অবজেক্ট তৈরি করতে হয় না।
কিন্তু যদি স্ট্যাটিক মেথডের মধ্যে আমরা ননস্ট্যাটিক মেম্বার গুলোকে অ্যাক্সেস করতে চাই তাহলে তো আমাদেরকে $this কিওয়ার্ডের সাহায্যে এদেরকে ব্যবহার করতে হবে। কিন্তু আমরা তো জানি স্ট্যাটিক মেথড এর মধ্যে $this কিওয়ার্ডকে ব্যবহার করা যায় না। কারণ $this কিওয়ার্ড তো অবজেক্টের সাথে রিলেটেড কিন্তু ননস্ট্যাটিক মেম্বার গুলো তো অবজেক্টের সাথে রিলেটেড না। ঠিক এই কারণেই মূলত ননস্ট্যাটিক মেথডের মধ্যে আমরা $this কিওয়ার্ড ব্যবহার করতে পারিনা।
কিন্তু কখনো যদি স্ট্যাটিক মেথডের মধ্যে ননস্ট্যাটিক মেম্বার গুলোকে ব্যবহার করার প্রয়োজন হয় সেক্ষেত্রে আমরা এই ক্লাসের একটি ইন্সটেন্স বা অবজেক্ট এই ননস্ট্যাটিক মেথডের মধ্যে ক্রিয়েট করতে পারি তারপর আমরা তাদেরকে ব্যবহার করতে পারব যেমনটা উপরের উদাহারণে দেখানো হয়েছে।
আশা করি $this এবং self কিওয়ার্ডের ব্যবহার সম্পর্কে আরেকটু পরিষ্কার ধারণা হয়েছে। তাহলে আজ এই পর্যন্তই, কথা হবে পরবর্তী লেছনে।