পিএইচপি ফাংশন - ইন্টারনালস এবং মেমোরি ম্যানেজমেন্ট
ফাংশন কেবল কোড রিইউজ করার মাধ্যম নয়। একজন সিনিয়র ডেভেলপার ফাংশনকে দেখেন Call Stack এবং Memory Scope এর দৃষ্টিতে।
এই অধ্যায়ে আমরা ফাংশনের ব্যবচ্ছেদ (Dissection) করব।
৩.১ ফাংশন মেমোরি স্ট্যাক (The Call Stack)
যখনই আপনি একটি ফাংশন কল করেন, র্যামের ভেতর একটি কর্মযজ্ঞ শুরু হয়। একে বলা হয় Execution Context বা Stack Frame।
📚 মেমোরিতে যা ঘটে:
- Push: ফাংশন কল হলে একটি নতুন "ফ্রেম" স্ট্যাকের ওপর জমা হয়
- Pop: ফাংশন return করলে সেই ফ্রেম মেমোরি থেকে মুছে যায়
📋 প্রতিটি স্ট্যাক ফ্রেমে কী থাকে?
- আর্গুমেন্ট ভ্যালু (Local Variables)
- রিটার্ন অ্যাড্রেস (কাজ শেষে কোথায় ফেরত যাবে)
- ফাংশন মেটাডেটা
💻 কোড ভিজ্যুয়ালাইজেশন:
function add($a, $b) {
$c = $a + $b; // ফ্রেমের ভেতর $a, $b, $c তৈরি হলো
return $c; // মেমোরি রিলিজ
}
add(5, 3);
⚠️ সতর্কতা (Recursion Limit):
রিকার্সিভ ফাংশনে যদি বেস কন্ডিশন না থাকে, তবে একের পর এক ফ্রেম জমা হতে থাকে। র্যামের স্ট্যাক লিমিট শেষ হলে পিএইচপি Fatal Error: Maximum function nesting level of '256' reached থ্রো করে। একেই বলে Stack Overflow।
৩.২ পাস-বাই-ভ্যালু বনাম রেফারেন্স (The Memory Game)
পিএইচপি ডিফল্টভাবে ভ্যালু কপি করে কাজ করে। কিন্তু সিনিয়রা জানে কখন রেফারেন্স ব্যবহার করতে হয়।
📦 ১. পাস-বাই-ভ্যালু (Pass-by-Value)
function inc($x) {
$x++; // এখানে $x হলো মূল ভেরিয়েবলের কপি
}
$a = 5;
inc($a); // $a এর মান ৫-ই থাকবে
ইন্টারনাল: শুরুতে $a এবং $x একই zval শেয়ার করে (Copy-On-Write)। কিন্তু ফাংশনের ভেতরে যখন $x++ করা হয়, তখনই মেমোরি স্প্লিট হয়ে আলাদা কপি তৈরি হয়।
🔗 ২. পাস-বাই-রেফারেন্স (Pass-by-Reference)
function inc(&$x) { // '&' মানে মেমোরি অ্যাড্রেস পাস করা
$x++;
}
$a = 5;
inc($a); // এখন $a এর মান ৬
ইন্টারনাল: এখানে $a এবং $x—দুটোই একই zval পয়েন্ট করে থাকে। কোনো ডুপ্লিকেট মেমোরি তৈরি হয় না।
❌ সিনিয়রের সতর্কতা (Reference Pitfall):
ফাংশন কলে সরাসরি ভ্যালু দেওয়া যাবে না যদি প্যারামিটার রেফারেন্স হয়।
function test(&$n) {}
test(10); // Fatal Error! কারণ 10 এর কোনো মেমোরি অ্যাড্রেস নেই।
৩.৩ ডিফল্ট প্যারামিটার ট্র্যাপ (Default Parameter Logic)
এখানে একটি সূক্ষ্ম বিষয় আছে। অন্য অনেক ল্যাঙ্গুয়েজের (যেমন Python) মতো পিএইচপি ডিফল্ট অ্যারে শেয়ার করে না, কিন্তু কনস্ট্যান্ট বা এক্সপ্রেশন ব্যবহারের সময় সাবধান হতে হয়।
⏰ Evaluation Time:
পিএইচপিতে ডিফল্ট ভ্যালু প্রতিটি ফাংশন কলের সময় ইভালুয়েট হয়।
✅ Senior Practice:
সবসময় অপশনাল প্যারামিটার ($param = null) লিস্টের শেষে রাখুন। পিএইচপি ৮-এর আগে এটি ওয়ার্নিং দিত না, কিন্তু এখন Deprecated Notice দেয়।
// ❌ Bad
function make($a = 1, $b) {}
// ✅ Good
function make($b, $a = 1) {}
৩.৪ ভ্যারিয়াডিক ফাংশন (Variadic Functions ...$args)
আধুনিক পিএইচপিতে func_get_args() ব্যবহার করা Bad Practice। সিনিয়রা ব্যবহার করেন ... (Splat Operator)।
function sum(...$nums) {
// $nums এখন অটোমেটিক্যালি একটি অ্যারে [1, 2, 3]
return array_sum($nums);
}
echo sum(1, 2, 3); // 6
🔄 আর্গুমেন্ট আনপ্যাকিং (Argument Unpacking):
উল্টোভাবে, আপনি একটি অ্যারেকে ফাংশনের আর্গুমেন্ট হিসেবেও পাঠাতে পারেন।
$data = [5, 10];
function add($a, $b) { return $a + $b; }
echo add(...$data); // PHP এটাকে add(5, 10) বানিয়ে ফেলবে
৩.৫ অ্যানোনিমাস ফাংশন ও ক্লোজার (Closures Deep Dive)
সিনিয়রের জন্য সবচেয়ে গুরুত্বপূর্ণ কনসেপ্ট। Closure হলো এমন একটি ফাংশন যা তার জন্মের সময়কার পরিবেশ (Variables) মনে রাখতে পারে।
🔧 use কিওয়ার্ডের ইন্টারনাল:
$tax = 10;
$calculate = function($price) use ($tax) {
return $price + $tax;
};
এখানে $tax ভেরিয়েবলটি ফাংশন ডিফাইন করার মুহূর্তে ক্লোজারের ভেতর By Value কপি হয়ে যায়।
📸 প্রমাণ (Snapshot Effect):
$msg = "Hello";
$say = function() use ($msg) { echo $msg; };
$msg = "World"; // মেইন ভেরিয়েবল চেঞ্জ হলো
$say(); // Output: "Hello" (পুরনো ভ্যালু ধরে রেখেছে!)
✅ Live Reference: যদি আপনি চান ক্লোজারটি লেটেস্ট ভ্যালু জানুক, তবে & ব্যবহার করতে হবে: use (&$msg)।
৩.৬ অ্যারো ফাংশন (Arrow Functions fn) - PHP 7.4+
অ্যারো ফাংশন হলো ক্লোজারের সংক্ষিপ্ত রূপ, কিন্তু এর মেমোরি বিহেভিয়ার আলাদা।
✨ Auto Capture:
use কিওয়ার্ড লাগে না। প্যারেন্ট স্কোপের ভেরিয়েবল সে অটোমেটিক পায়।
📦 By Value Only:
অ্যারো ফাংশন প্যারেন্ট ভেরিয়েবলকে সবসময় By Value ক্যাপচার করে। আপনি চাইলেও fn এর ভেতর বাইরের ভেরিয়েবল মডিফাই করতে পারবেন না।
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3]);
// $factor অটোমেটিক অ্যাভেলেবল
৩.৭ টাইপ হিন্টিং এবং স্ট্রিক্ট টাইপস (The Seatbelt)
পিএইচপিকে "Loose Language" বলা হয়, কিন্তু এন্টারপ্রাইজ লেভেলে আমরা একে "Strict" বানিয়ে ফেলি।
📄 declare(strict_types=1);
এই লাইনটি ফাইলের একদম শুরুতে লিখতে হয়। এটি না থাকলে পিএইচপি জোর করে টাইপ কনভার্ট করে।
📦 Non-Strict (Default):
function add(int $a, int $b) { return $a + $b; }
add("5", "10"); // কাজ করবে, আউটপুট 15 (String to Int Conversion)
⚠️ Strict Mode:
declare(strict_types=1);
add("5", "10"); // ❌ Fatal Error: TypeError
✅ কেন সিনিয়রা এটা ব্যবহার করে?
অটোমেটিক কনভার্সন অনেক সময় ডাটা লস করে (যেমন "100 apples" হয়ে যায় 100)। স্ট্রিক্ট মোড বাগ আগেভাগে ধরে ফেলে।
🎯 Senior Developer Interview Questions (Part 3)
Q: একটি Closure-এর ভেতর বাইরের ভেরিয়েবল use করলে সেটি কি Reference হিসেবে আসে নাকি Value হিসেবে?
ডিফল্টভাবে Value (কপি) হিসেবে আসে। অর্থাৎ ক্লোজার তৈরির পর বাইরের ভেরিয়েবল বদলালেও ক্লোজারের ভেতর তা বদলায় না। রেফারেন্স চাইলে & দিতে হয়।
Q: Arrow Function (fn) এবং Anonymous Function-এর মধ্যে মেমোরি স্কোপিংয়ের পার্থক্য কী?
Arrow function প্যারেন্ট স্কোপের ভেরিয়েবল অটোমেটিক্যালি By Value ক্যাপচার করে। Anonymous function এ use কিওয়ার্ড দিয়ে ম্যানুয়ালি বলে দিতে হয়।
Q: Stack Overflow এরর কেন হয়? পিএইচপিতে এটি কীভাবে হ্যান্ডেল করা হয়?
রিকার্সিভ ফাংশন বা অসীম লুপে ফাংশন কল হতে থাকলে Call Stack পূর্ণ হয়ে যায়। পিএইচপি xdebug.max_nesting_level বা memory_limit দিয়ে এটি নিয়ন্ত্রণ করে।
🎯 অধ্যায় ৩ এর সারাংশ (Summary)
এই অধ্যায়ে আমরা শিখলাম:
- ✓Call Stack: ফাংশন কল = Stack Frame Push/Pop
- ✓Pass-by-Value/Reference: COW vs Shared Memory
- ✓Variadic Functions: ...$splat operator
- ✓Closures: use() by value, & reference for live update
- ✓Arrow Functions (fn): Auto capture, by value only
- ✓Strict Types: declare(strict_types=1) prevents automatic conversion
✨ পরবর্তী অধ্যায়: Part 4 - Arrays & Internal Data Structures — যেখানে হ্যাশটেবল, SPL এবং মেমোরি অপ্টিমাইজেশন নিয়ে আলোচনা হবে।
প্রস্তুত তো? 🚀