PHP സെർവർ സൈഡിൽ ഒരുപാട് ആവർത്തന ജോലികൾ (repetitive work) കൈകാര്യം ചെയ്യുന്നു. ഒരു സിംഗിൾ റിക്വസ്റ്റ് ഇമേജുകൾ നിറഞ്ഞ ഒരു ഫോൾഡർ സ്കാൻ ചെയ്യേണ്ടി വന്നേക്കാം, അല്ലെങ്കിൽ ഒരു സ്റ്റാറ്റസ് മാറുന്നത് വരെ ഡാറ്റാബേസ് പരിശോധിക്കേണ്ടി വന്നേക്കാം, അതുമല്ലെങ്കിൽ നിശ്ചിത നിയമങ്ങൾ പാലിക്കുന്നത് വരെ ഉപയോക്താവിൽ നിന്ന് ഇൻപുട്ട് ചോദിച്ചുകൊണ്ടിരിക്കേണ്ടി വന്നേക്കാം. ഇത്തരത്തിലുള്ള കാര്യങ്ങൾ ഒരേ കോഡ് ബ്ലോക്ക് തന്നെ കോപ്പി പേസ്റ്റ് ചെയ്ത് ചെയ്യുന്നത് കോഡിനെ ദുർബലമാക്കുകയും മെയിന്റൈൻ ചെയ്യാൻ പ്രയാസകരമാക്കുകയും ചെയ്യും. ഈ പ്രശ്നം പരിഹരിക്കാനാണ് ലൂപ്പുകൾ (loops) ഉപയോഗിക്കുന്നത്. അവ ലോജിക്കിനെ ഒരു പുനരുപയോഗിക്കാവുന്ന (reusable) ബ്ലോക്കിനുള്ളിലാക്കി, പിശകുകൾ കുറയ്ക്കുകയും നിങ്ങളുടെ ആപ്ലിക്കേഷൻ കൂടുതൽ ലളിതമാക്കുകയും ചെയ്യുന്നു.
എത്ര തവണ ലൂപ്പ് പ്രവർത്തിക്കണം എന്ന് അറിയാമെങ്കിൽ മിക്കവാറും PHP ഡെവലപ്പർമാർ ഒരു for ലൂപ്പും, ഒരു ഡൈനാമിക് കണ്ടീഷൻ അനുസരിച്ചാണ് ആവർത്തനങ്ങൾ എന്ന് അറിയാത്തവർ while ലൂപ്പും ഉപയോഗിക്കുന്നു. എന്നാൽ ഇതിന് പുറമെ മൂന്നാമതൊരു ഓപ്ഷൻ കൂടിയുണ്ട്. അത് വ്യത്യസ്തമായ രീതിയിലാണ് പ്രവർത്തിക്കുന്നത്, അതിനാൽ ശരിയായ സമയത്ത് അത് ഉപയോഗിക്കുന്നത് നിങ്ങളുടെ കോഡിനെ കൂടുതൽ വ്യക്തമാക്കും. do-while ലൂപ്പ് ആദ്യം അതിന്റെ ബ്ലോക്കിനുള്ളിലെ കോഡ് പ്രവർത്തിപ്പിക്കുന്നു, അതിനുശേഷം മാത്രമേ അത് വീണ്ടും പ്രവർത്തിപ്പിക്കണോ എന്ന് പരിശോധിക്കുന്നുള്ളൂ.
എന്താണ് do-while ലൂപ്പിനെ വ്യത്യസ്തമാക്കുന്നത്
ഒരു സാധാരണ while ലൂപ്പിൽ, ബ്ലോക്കിനുള്ളിലേക്ക് പ്രവേശിക്കുന്നതിന് മുമ്പ് തന്നെ PHP കണ്ടീഷൻ പരിശോധിക്കുന്നു. കണ്ടീഷൻ തെറ്റാണെങ്കിൽ (false), ആ ബ്ലോക്ക് പൂർണ്ണമായും ഒഴിവാക്കപ്പെടും. എന്നാൽ do-while ലൂപ്പ് ഈ ക്രമം മാറ്റുന്നു. ഇത് ആദ്യം കോഡ് ഒരു തവണ പ്രവർത്തിപ്പിക്കുന്നു, അതിനുശേഷം മാത്രമേ ലൂപ്പ് വീണ്ടും പ്രവർത്തിപ്പിക്കണോ എന്ന് തീരുമാനിക്കാൻ കണ്ടീഷൻ പരിശോധിക്കുന്നുള്ളൂ.
ഇതിന്റെ സിന്റാക്സ് (syntax) ഇപ്രകാരമാണ്:
do {
// statements
} while ($condition);
while ക്ലോസിന് ശേഷമുള്ള സെമി കോളൻ (semicolon) ശ്രദ്ധിക്കുക. ആ സെമി കോളൻ നിർബന്ധമാണ്, അത് മറന്നുപോയാൽ സിന്റാക്സ് എറർ (syntax error) വരും. കണ്ടീഷൻ തുടക്കത്തിൽ തന്നെ തെറ്റാണെങ്കിൽ പോലും, do ഉം while ഉം തമ്മിലുള്ള ബ്ലോക്ക് കുറഞ്ഞത് ഒരു തവണയെങ്കിലും പ്രവർത്തിക്കും. ഈ രീതി വെറുമൊരു പ്രത്യേകതയല്ല; ഈ ലൂപ്പ് നിലനിൽക്കുന്നതിന്റെ പ്രധാന കാരണവും ഇതുതന്നെയാണ്.
എപ്പോഴാണ് do-while ഉപയോഗിക്കേണ്ടത്
ഈ ഘടന ഏറ്റവും അനുയോജ്യമായ മൂന്ന് സാഹചര്യങ്ങളുണ്ട്: ഒരു മെനു പ്രദർശിപ്പിക്കുക, ഇൻപുട്ട് പരിശോധിക്കുക (validating input), പരാജയപ്പെടാൻ സാധ്യതയുള്ള ഒരു കാര്യം വീണ്ടും ശ്രമിക്കുക (retrying a task). ഈ ഓരോ സാഹചര്യത്തിലും, പ്രവർത്തനം തുടരണോ എന്ന് തീരുമാനിക്കുന്നതിന് മുമ്പ് ആ പ്രവർത്തനം നടന്നു കഴിഞ്ഞിരിക്കണം എന്നതാണ് ലോജിക് ആവശ്യപ്പെടുന്നത്.
ഒരു മെനു പ്രദർശിപ്പിക്കുക
ഒരു കമാൻഡ്-ലൈൻ ടൂളോ ടെക്സ്റ്റ് അധിഷ്ഠിത അഡ്മിൻ പാനലോ സങ്കൽപ്പിക്കുക. നിങ്ങൾക്ക് ഓപ്ഷനുകളുടെ ഒരു ലിസ്റ്റ് പ്രിന്റ് ചെയ്യണം, ഉപയോക്താവ് ഒന്ന് തിരഞ്ഞെടുക്കുന്നത് വരെ കാത്തിരിക്കണം, അതിനുശേഷം മെനു വീണ്ടും കാണിക്കണോ എന്ന് തീരുമാനിക്കണം. മെനു സ്ക്രീനിൽ തെളിയുന്നതിന് മുമ്പ് ഉപയോക്താവ് 'exit' തിരഞ്ഞെടുത്തോ എന്ന് നിങ്ങൾക്ക് പരിശോധിക്കാൻ കഴിയില്ല.
$choice = 0;
do {
echo "1. View Reports\n";
echo "2. Export Data\n";
echo "3. Exit\n";
$choice = (int) readline("Select an option: ");
if ($choice === 1) {
// fetch and display reports
} elseif ($choice === 2) {
// run export logic
}
} while ($choice !== 3);
ഒരു സാധാരണ while ലൂപ്പ് സാങ്കേതികമായി ഇത് കൈകാര്യം ചെയ്തേക്കാം, പക്ഷേ ലൂപ്പ് തുടങ്ങുന്നതിന് മുമ്പ് മെനു ഔട്ട്പുട്ട് ഒരിക്കൽ കൂടി ആവർത്തിക്കേണ്ടി വരും, അല്ലെങ്കിൽ ആദ്യത്തെ കണ്ടീഷൻ ശരിയാക്കാൻ വേണ്ടി $choice എന്ന വേരിയബിളിന് ഒരു വ്യാജ മൂല്യം (phony value) നൽകേണ്ടി വരും. ഇത് ഒരേ ലോജിക് രണ്ട് സ്ഥലങ്ങളിൽ ചിതറിക്കിടക്കാൻ കാരണമാകും. എന്നാൽ do-while ഉപയോഗിക്കുമ്പോൾ ഡിസ്പ്ലേ, റീഡ്, ചെക്ക് എന്നിവയെല്ലാം ഒരൊറ്റ ബ്ലോക്കിനുള്ളിൽ വൃത്തിയായി സൂക്ഷിക്കാം.
ഇൻപുട്ട് പരിശോധിക്കുക
ഇൻപുട്ട് പരിശോധിക്കുന്ന രീതിയും സമാനമാണ്. ഉപയോക്താവിനോട് ഇൻപുട്ട് ചോദിക്കണം, അവർ നൽകിയത് പരിശോധിക്കണം, അത് നിയമങ്ങൾ പാലിക്കുന്നില്ലെങ്കിൽ വീണ്ടും ചോദിക്കണം. പരിശോധനയ്ക്ക് മുമ്പ് തന്നെ ഇൻപുട്ട് ചോദിക്കണം എന്നതുകൊണ്ട് do-while ലൂപ്പ് ഇതിന് സ്വാഭാവികമായി യോജിക്കുന്നു.
do {
$username = readline("Choose a username (min 3 chars): ");
$isValid = strlen($username) >= 3;
if (!$isValid) {
echo "That username is too short.\n";
}
} while (!$isValid);
ഒരു സാധാരണ while ലൂപ്പ് ഉപയോഗിക്കുകയാണെങ്കിൽ, കണ്ടീഷൻ പരിശോധിക്കാൻ വേണ്ടി $username എന്ന വേരിയബിളിന് ഒരു ശൂന്യമായ സ്ട്രിംഗ് (empty string) നൽകേണ്ടി വരും, കൂടാതെ ലൂപ്പിന് മുകളിൽ പ്രോംപ്റ്റ് ലൈൻ വീണ്ടും എഴുതേണ്ടി വരും. ഈ ആവർത്തനം പിശകുകൾക്ക് (bugs) കാരണമായേക്കാം. പിന്നീട് നിങ്ങൾ പ്രോംപ്റ്റ് മെസ്സേജ് മാറ്റുകയാണെങ്കിൽ, ലൂപ്പിനുള്ളിലെ മാറ്റം ശ്രദ്ധിച്ചേക്കാം, പക്ഷേ അതിനു മുകളിലുള്ള കോപ്പി മാറ്റാൻ മറന്നുപോയേക്കാം. എന്നാൽ do-while ഘടന ഈ റിസ്ക് ഒഴിവാക്കുന്നു; കാരണം കണ്ടീഷൻ പരിശോധിക്കുന്നതിന് മുമ്പ് തന്നെ പ്രോംപ്റ്റ് ബ്ലോക്കിനുള്ളിൽ പ്രവർത്തിക്കുമെന്ന് ഇത് ഉറപ്പാക്കുന്നു.
പരാജയപ്പെട്ട ഒരു കാര്യം വീണ്ടും ശ്രമിക്കുക
നെറ്റ്വർക്ക് റിക്വസ്റ്റുകൾ, ഫയൽ ലോക്കുകൾ, ഡാറ്റാബേസ് റൈറ്റുകൾ എന്നിവ ചിലപ്പോൾ ആദ്യ ശ്രമത്തിൽ പരാജയപ്പെടാം, എന്നാൽ തൊട്ടുപിന്നാലെ വിജയിച്ചേക്കാം. സാധാരണയായി നിങ്ങൾ ഒരു തവണയെങ്കിലും ശ്രമിക്കാൻ ആഗ്രഹിക്കും, തുടർന്ന് പരാജയം തുടരുന്നിടത്തോളം കാലം വീണ്ടും ശ്രമിക്കുകയും ചെയ്യും.
$attempts = 0;
$maxRetries = 3;
$success = false;
do {
$attempts++;
$response = @file_get_contents('https://api.example.com/status');
if ($response !== false) {
$success = true;
} elseif ($attempts < $maxRetries) {
sleep(1);
}
} while (!$success && $attempts < $maxRetries);
if (!$success) {
// log the permanent failure
}
ഇവിടെ ശ്രദ്ധിക്കേണ്ട പ്രധാന കാര്യം, "ഇത് വിജയിച്ചോ?" എന്ന് PHP ചോദിക്കുന്നതിന് മുമ്പ് തന്നെ റിക്വസ്റ്റ് അയക്കപ്പെടുന്നു എന്നതാണ്. ഒരു while ലൂപ്പ് ഉപയോഗിക്കുകയാണെങ്കിൽ, ലൂപ്പിലേക്ക് പ്രവേശിക്കുന്നതിന് മുമ്പ് ഒരു ഡമ്മി റിക്വസ്റ്റ് അയക്കുകയോ അല്ലെങ്കിൽ ഒരു വ്യാജ സക്സസ് ഫ്ലാഗ് (fake success flag) സെറ്റ് ചെയ്യുകയോ ചെയ്യേണ്ടി വരും, ഇത് യഥാർത്ഥത്തിൽ എന്താണ് സംഭവിക്കുന്നത് എന്ന് വ്യക്തമാക്കാതെയാക്കും. എന്നാൽ do-while രീതി കൂടുതൽ കൃത്യമാണ്: ശ്രമിക്കുക, പരിശോധിക്കുക, തീരുമാനിക്കുക.
do-while ഉം while ഉം തമ്മിലുള്ള താരതമ്യം
ഈ രണ്ട് ലൂപ്പുകളും തമ്മിലുള്ള വ്യത്യാസം സമയക്രമത്തിലാണ് (timing). ഒരു ടെസ്റ്റിൽ പരാജയപ്പെടാൻ സാധ്യതയുള്ള ഒരു വേരിയബിൾ പരിഗണിക്കുക:
$x = 10;
while ($x < 5) {
echo $x; // Never runs
}
അതേ സ്റ്റാർട്ടിംഗ് വാല്യൂ ഉപയോഗിച്ച് ഒരു do-while ലൂപ്പ് ഇപ്രകാരമാണ് പ്രവർത്തിക്കുന്നത്:
$x = 10;
do {
echo $x; // Runs once, outputs 10
} while ($x < 5);
ഒരു തവണയെങ്കിലും കോഡ് പ്രവർത്തിക്കുമെന്ന ഉറപ്പാണ് ഇതിലെ പ്രധാന വ്യത്യാസം. നിങ്ങളുടെ ലോജിക് പൂജ്യം അല്ലെങ്കിൽ അതിലധികം തവണ പ്രവർത്തിക്കണമെങ്കിൽ while ആണ് സുരക്ഷിതമായ മാർഗ്ഗം. എന്നാൽ ലോജിക് ഒരു തവണയെങ്കിലും പ്രവർത്തിക്കണമെങ്കിൽ do-while ആണ് കൂടുതൽ അനുയോജ്യം.
Pitfalls and Best Practices
do-while ലൂപ്പ് കുറഞ്ഞത് ഒരു തവണയെങ്കിലും പ്രവർത്തിക്കുമെന്ന് ഉറപ്പുനൽകുന്നതുകൊണ്ട്, നിങ്ങൾ ശ്രദ്ധിച്ചില്ലെങ്കിൽ അത് ഒരു ഇൻഫിനിറ്റ് ലൂപ്പും (infinite loop) ആയി മാറാൻ സാധ്യതയുണ്ട്. കണ്ടീഷനിൽ പരിശോധിക്കുന്ന വേരിയബിളുകൾ ബ്ലോക്കിനുള്ളിൽ മാറുന്നില്ലെങ്കിൽ, PHP അത് അനന്തമായി പ്രവർത്തിച്ചുകൊണ്ടിരിക്കും അല്ലെങ്കിൽ മാക്സിമം എക്സിക്യൂഷൻ ടൈം (maximum execution time) എത്തുന്നതുവരെ തുടരും.
അവസാനത്തെ സെമി കോളൻ (semicolon) ഒഴിവാക്കുന്നതും മറ്റൊരു സാധാരണ തെറ്റാണ്. താഴെ പറയുന്ന രീതി പരാജയപ്പെടും:
do {
// code
} while ($x < 5) // syntax error
മറ്റൊരു ലൂപ്പ് കൂടുതൽ വ്യക്തത നൽകുന്ന സാഹചര്യത്തിൽ, വെറുതെ ഒരു ശീലത്തിന്റെ ഭാഗമായി do-while ഉപയോഗിക്കുന്നത് ഒഴിവാക്കണം. നിങ്ങൾ ഒരു അറേയിലൂടെ (array) ഇറ്ററേഷൻ നടത്തുകയാണെങ്കിൽ, foreach ഉപയോഗിക്കുന്നതാണ് എപ്പോഴും നല്ലത്. ഒരു ലളിതമായ നമ്പറിക് കൗണ്ടർ (numeric counter) കൈകാര്യം ചെയ്യുകയാണെങ്കിൽ, for ലൂപ്പ് ഉപയോഗിക്കുന്നത് ഇനീഷ്യലൈസേഷൻ (initialization), കണ്ടീഷൻ (condition), ഇൻക്രിമെന്റ് (increment) എന്നിവ ഒരൊറ്റ വരിയിൽ നിലനിർത്താൻ സഹായിക്കും, ഇത് കോഡ് പെട്ടെന്ന് മനസ്സിലാക്കാൻ എളുപ്പമാണ്.
പെർഫോമൻസിന്റെ (performance) കാര്യത്തിൽ, PHP-യിൽ while ലൂപ്പിനെ അപേക്ഷിച്ച് do-while ലൂപ്പിന് പ്രത്യേകമായ ഭാരമില്ല (overhead). ഇതിന്റെ ഗുണം പൂർണ്ണമായും അതിന്റെ ഘടനയിലാണ് (structural). മറ്റൊരു ഡെവലപ്പർ ഒരു do-while ലൂപ്പ് കാണുമ്പോൾ, ഏതെങ്കിലും കണ്ടീഷൻ പരിശോധിക്കുന്നതിന് മുമ്പ് ആ ബ്ലോക്ക് പ്രവർത്തിക്കണമെന്ന് അവർക്ക് പെട്ടെന്ന് മനസ്സിലാകും. ഈ ഒരു വിവരം, ഒരു സാധാരണ while ലൂപ്പിന് മുകളിൽ ഡമ്മി വേരിയബിളുകൾ (dummy variables) പരിശോധിക്കുന്നതിനോ അല്ലെങ്കിൽ ആവർത്തിച്ചുള്ള സെറ്റപ്പ് കോഡുകൾ (duplicated setup code) നോക്കുന്നതിനോ ഉള്ള സമയം ലാഭിക്കാൻ അവരെ സഹായിക്കുന്നു.
എഡ്ജ് കേസുകളും (Edge Cases) മറ്റ് രീതികളും
ചിലപ്പോൾ ഉപയോക്താവിന്റെ ഇടപെടൽ (user interaction) ഇല്ലാത്ത സാഹചര്യങ്ങളിൽ പോലും do-while ലൂപ്പ് ഉപയോഗപ്രദമാണ്. ഉദാഹരണത്തിന്, കുറഞ്ഞത് ഒരു ഐറ്റം എങ്കിലും നൽകുന്ന ഒരു ജനറേറ്ററോ (generator) അല്ലെങ്കിൽ കർസറോ (cursor) ഉപയോഗിക്കുമ്പോൾ, നിങ്ങൾക്ക് ആദ്യത്തെ ഐറ്റം പ്രോസസ്സ് ചെയ്ത ശേഷം കർസർ അടുത്ത ശരിയായ സ്ഥാനത്തേക്ക് മാറിയോ എന്ന് പരിശോധിക്കാം. മോഡേൺ റിസൾട്ട് സെറ്റുകൾക്ക് (result sets) പകരം റോ ഡാറ്റാബേസ് റിസോഴ്സുകൾ (raw database resources) ഉപയോഗിക്കുന്ന പഴയ കോഡ്ബേസുകളിൽ (legacy codebases) ഇത്തരത്തിലുള്ള ഒരു രീതി കാണാൻ സാധിക്കും:
$row = $result->fetch();
do {
// process $row
} while ($row = $result->fetch());
ആധുനിക PHP-യിൽ PDO-യോടൊപ്പം foreach ഉപയോഗിക്കുന്നതിനാണ് മുൻഗണന നൽകുന്നത് എങ്കിലും, അധികമായ ബ്രാഞ്ചിംഗ് (branching) ഇല്ലാതെ തന്നെ ആദ്യത്തെ ഇറ്ററേഷനെ (iteration) ഒരു പ്രത്യേക സാഹചര്യമായി എങ്ങനെ do-while കൈകാര്യം ചെയ്യുന്നു എന്ന് ഈ രീതി കാണിച്ചുതരുന്നു.
പ്രധാനമായും ശ്രദ്ധിക്കേണ്ട കാര്യം
do-while ലൂപ്പ് ഒരു പരിമിതമായ ഉപയോഗമുള്ള ടൂൾ ആണ്, എന്നാൽ ശരിയായ സാഹചര്യത്തിൽ അത് മാത്രമാണ് ഏറ്റവും അനുയോജ്യമായ മാർഗ്ഗം. ഇത് നിങ്ങളുടെ സെറ്റപ്പ് (setup), വാലിഡേഷൻ ലോജിക് (validation logic) എന്നിവ ഒരിടത്ത് തന്നെ നിലനിർത്തുന്നു, ഒരു കാര്യം വിലയിരുത്തുന്നതിന് മുമ്പ് അത് ചെയ്യാൻ ശ്രമിക്കുന്നുണ്ടെന്ന് ഉറപ്പാക്കുന്നു, കൂടാതെ കോഡ് വായിക്കുന്ന അടുത്ത വ്യക്തിക്ക് നിങ്ങളുടെ ഉദ്ദേശ്യം നേരിട്ട് മനസ്സിലാക്കിക്കൊടുക്കുന്നു. ഒരു പ്രവൃത്തി ചെയ്തതിന് ശേഷം വേണം കണ്ടീഷൻ പരിശോധിക്കേണ്ടത് എന്നുണ്ടെങ്കിൽ do-while ഉപയോഗിക്കുക. മറ്റെല്ലാ സാഹചര്യങ്ങളിലും ലളിതമായ while, for, അല്ലെങ്കിൽ foreach ഉപയോഗിക്കുന്നതാണ് ഉചിതം.
