স্ট্রিং এবং রেগুলার এক্সপ্রেশন (The Silent Performance Killers)
স্ট্রিং ম্যানিপুলেশন যেকোনো অ্যাপ্লিকেশনের অন্যতম প্রধান কাজ। কিন্তু পিএইচপি-তে স্ট্রিং এবং রিজেক্স (Regex) সঠিকভাবে হ্যান্ডেল না করলে মেমোরি লিক এবং CPU স্পাইক হতে পারে।
এই অধ্যায়ে আমরা স্ট্রিং-এর বাইনারি লেভেল এবং PCRE ইঞ্জিনের গভীরে প্রবেশ করব।
৫.১ স্ট্রিং ইন্টারনাল আর্কিটেকচার (Byte Sequence)
পিএইচপি-তে স্ট্রিং হলো Immutable Binary-Safe Byte Sequence। সহজ কথায়, পিএইচপি স্ট্রিং-কে ক্যারেক্টার হিসেবে চেনে না, চেনে বাইট (Byte) হিসেবে।
📦 মেমোরি মডেল এবং Immutability
পিএইচপি স্ট্রিং Immutable (অপরিবর্তনযোগ্য)। এর মানে হলো, আপনি যখনই কোনো স্ট্রিং পরিবর্তন করেন, পিএইচপি মেমোরিতে সম্পূর্ণ নতুন একটি স্ট্রিং তৈরি করে।
$str = "Hello";
$str[0] = "J"; // Internally: নতুন মেমোরি অ্যালোকেট হয়, পুরনোটা ফেলে দেওয়া হয় না (COW)
📏 সাইজ বনাম মেমোরি (Overhead)
আপনি যদি ১ মেগাবাইটের একটি স্ট্রিং তৈরি করেন, তবে র্যামে ঠিক ১ মেগাবাইট জায়গা খরচ হয় না।
$str = str_repeat("A", 1_000_000); // 1 Million Bytes
// Actual RAM usage: ~1.04 MB (Zval structure + Metadata overhead)
প্রতিটি স্ট্রিংয়ের সাথে পিএইচপি কিছু মেটাডেটা (Length, Refcount) রাখে, তাই সাইজ সবসময় একটু বেশি হয়।
৫.২ স্ট্রিং ম্যানিপুলেশন এবং মেমোরি অপ্টিমাইজেশন
❌ ১. কনক্যাটিনেশন (Concatenation) এর বিপদ
বড় টেক্সট জেনারেট করার সময় ডট (.) অপারেটর ব্যবহার করা মেমোরির জন্য ক্ষতিকর।
// ❌ Bad Practice (High Memory Churn)
$html = "";
foreach ($data as $row) {
$html .= "" . $row . "";
// প্রতি লুপে আগের $html কপি হচ্ছে + নতুন পার্ট যোগ হচ্ছে = মেমোরি ওয়েস্ট
}
✅ Senior Way (Buffer Method):
$buffer = [];
foreach ($data as $row) {
$buffer[] = "" . $row . "";
}
$html = implode("", $buffer);
// মাত্র একবার মেমোরি অ্যালোকেশন হয়। বড় ডেটার জন্য এটি অনেক ফাস্ট।
⚡ ২. strpos বনাম preg_match
সিম্পল সার্চের জন্য কখনোই preg_match ব্যবহার করবেন না।
strpos: O(n) (C-level byte scan, অত্যন্ত ফাস্ট)preg_match: Regex ইঞ্জিন লোড করে, প্যাটার্ন কম্পাইল করে, তারপর সার্চ করে (১০-২০ গুণ স্লো)
৫.৩ রেগুলার এক্সপ্রেশন: পারফরম্যান্স রুলস (PCRE Engine)
পিএইচপি PCRE (Perl Compatible Regular Expressions) লাইব্রেরি ব্যবহার করে। এটি শক্তিশালী কিন্তু ভারী।
🔄 Regex এক্সিকিউশন স্টেপস:
- Compilation: প্যাটার্নটি ইন্টারনাল বাইটকোডে কম্পাইল হয়
- Execution: ইঞ্জিন ইনপুট স্ট্রিং স্ক্যান করে
- Backtracking: ম্যাচ না পেলে সে পেছনে ফিরে আবার চেষ্টা করে
⚠️ Catastrophic Backtracking (সার্ভার হ্যাং করার উপায়)
সবচেয়ে ভয়ংকর Regex প্যাটার্ন হলো নেস্টেড কোয়ান্টিফায়ার।
// ❌ DANGEROUS CODE
preg_match('/(a+)+b/', "aaaaaaaaaaaaaaaaaaaaac");
কেন এটি বিপজ্জনক?
এখানে (a+)+ প্যাটার্নটি a-কে গ্রাস করে। শেষে b না পেয়ে সে এক ধাপ পেছনে যায়, আবার চেষ্টা করে। ৫০০০ ক্যারেক্টারের জন্য এটি $2^{5000}$ বার চেষ্টা করতে পারে! একে বলা হয় Catastrophic Backtracking। এটি আপনার CPU 100% করে সার্ভার ডাউন করে দেবে।
💡 Senior Rule: কখনোই নেস্টেড লুপের মতো (x+)+ প্যাটার্ন লিখবেন না।
৫.৪ preg_replace বনাম str_replace
সিনিয়দের গোল্ডেন রুল: "যদি Regex ছাড়া কাজ হয়, তবে Regex ব্যবহার করবেন না।"
❌ Slow
preg_replace('/World/', 'PHP', $text);
✅ Fast (20x Faster)
str_replace('World', 'PHP', $text);
📋 তুলনা:
str_replace: কোনো কম্পাইলেশন নেই, সরাসরি ক্যারেক্টার রিপ্লেস করে। সুপার ফাস্টpreg_replace: প্যাটার্ন কম্পাইল করে, ম্যাচ খোঁজে, নতুন স্ট্রিং তৈরি করে
📞 preg_replace_callback
যখন ডাইনামিক লজিক দরকার হয়, তখন এটি ব্যবহার করুন। এটি e মডিফায়ার (যা এখন ডেপ্রিকেটেড) এর চেয়ে নিরাপদ।
৫.৫ UTF-8 এবং মাল্টি-বাইট ট্র্যাপ (The Most Common Bug)
পিএইচপি স্ট্রিং বাইট-বেইজড, ক্যারেক্টার-বেইজড নয়। এই পার্থক্য না বুঝলে ইমোজি বা বাংলা টেক্সট নিয়ে কাজ করা অসম্ভব।
📏 ১. strlen বনাম mb_strlen
$str = "বাংলা"; // ৩টি অক্ষর মনে হলেও আসলে ৫টি কোডপয়েন্ট
echo strlen($str); // Output: 15 (প্রতি বাংলা অক্ষর ৩ বাইট করে)
echo mb_strlen($str); // Output: 5 (সঠিক ক্যারেক্টার কাউন্ট)
শিক্ষা: ইউজার ইনপুট বা পাসওয়ার্ড লেন্থ চেক করতে সবসময় mb_strlen ব্যবহার করুন।
✂️ ২. substr এর বিপদ (Mojibake)
$text = "Hello বাংলা";
echo substr($text, 0, 7);
// Output: "Hello " (Broken character - মাল্টি-বাইট ক্যারেক্টার অর্ধেক কেটে ফেলেছে)
substr বাইট কেটে ফেলে, তাই মাল্টি-বাইট ক্যারেক্টারের মাঝখানে কেটে ফেললে স্ট্রিং করাপ্ট হয়ে যায়।
সমাধান: mb_substr($text, 0, 7, "UTF-8") ব্যবহার করুন।
🔍 ৩. Regex এবং UTF-8 (u modifier)
ডিফল্টভাবে Regex ইঞ্জিন বাইট ধরে কাজ করে। বাংলা বা ইমোজি ঠিকঠাক ম্যাচ করাতে u মডিফায়ার ব্যবহার করতে হয়।
// ❌ ভুল
preg_match('/^[w]+$/', "বাংলা"); // false (কারণ w শুধু a-z, 0-9 চেনে)
// ✅ সঠিক
preg_match('/^[p{L}]+$/u', "বাংলা"); // true (p{L} মানে যেকোনো ভাষার অক্ষর)
🎯 Senior Developer Interview Questions (Chapter 5)
Q: strlen("🔥") এর আউটপুট কত এবং কেন?
আউটপুট 4। কারণ পিএইচপি বাইট কাউন্ট করে, আর ইমোজিটি UTF-8 এনকোডিংয়ে ৪ বাইট জায়গা নেয়। সঠিক ক্যারেক্টার কাউন্ট পেতে mb_strlen ব্যবহার করতে হবে।
Q: Catastrophic Backtracking কী? একটি উদাহরণ দিন।
যখন একটি Regex প্যাটার্নে নেস্টেড কোয়ান্টিফায়ার থাকে (যেমন /(a+)+b/) এবং ইনপুট স্ট্রিং প্রায় ম্যাচ করে কিন্তু শেষে ফেইল করে, তখন ইঞ্জিন এক্সপোনেনশিয়াল টাইম (O(2^n)) নিয়ে ব্যাকট্র্যাক করে, যা সিস্টেম ফ্রিজ করে দেয়।
Q: বড় স্ট্রিং কনক্যাটিনেশনের জন্য . অপারেটরের চেয়ে implode কেন ভালো?
. অপারেটর প্রতি স্টেপে পুরনো স্ট্রিং কপি করে এবং নতুন মেমোরি অ্যালোকেট করে। implode বা array বাফারিং ব্যবহার করলে মেমোরি অ্যালোকেশন মাত্র একবার হয়, যা পারফরম্যান্স বাড়ায়।
Q: preg_replace বনাম str_replace - কখন কোনটি ব্যবহার করবেন?
যদি প্যাটার্ন ফিক্সড স্ট্রিং হয়, তবে সবসময় str_replace (ফাস্ট)। যদি প্যাটার্ন জটিল হয় (যেমন ওয়াইল্ডকার্ড বা রেঞ্জ), কেবল তখনই preg_replace ব্যবহার করা উচিত।
🎯 অধ্যায় ৫ এর সারাংশ (Summary)
এই অধ্যায়ে আমরা শিখলাম:
- ✓String Internals: পিএইচপি স্ট্রিং বাইট-বেইজড (Binary-safe), Immutable
- ✓Concatenation Optimization: . অপারেটরের বদলে implode() ব্যবহার করুন
- ✓strpos vs preg_match: Simple search এর জন্য strpos 20x faster
- ✓Catastrophic Backtracking: Nested quantifier (a+)+ সার্ভার হ্যাং করতে পারে
- ✓UTF-8 Traps: mb_strlen, mb_substr, এবং u modifier ব্যবহার করুন
- ✓preg_replace vs str_replace: Static replace-এ str_replace 20x faster
✨ পরবর্তী অধ্যায়: Part 6 — OOP (Full Senior Level) — যেখানে LSP (Liskov Substitution), Late Static Binding, Dependency Injection এবং আরও অনেক কিছু নিয়ে আলোচনা হবে।
প্রস্তুত তো? 🚀