Turinys
Straipsnio auditorija

Įvadas


21. neteisingas printf() funkcijos panaudojimas
20. netaisiklingas semantikos supratimas bei pritaikymas
19. nepakankamas arba per didelis php išeities kodo komentavimas
18. per daug laikinų kintamųjų
17. perrašome standartines funkcijas
16. klientinė kodo dalis maišoma su serveryje atliekamu kodu
15. pasenusios php sintaksės naudojimas


Reziumė

Apie autorių

Straipsnio auditorija

Šios straipsnio dalys skirtos php programuotojams, kurie nori išvengti dažniausiai php programuotojų daromų klaidų rašant kodą. Straipsnio skaitytojas turi žinoti php sintaksę, bei turėti praktikos programuojant php.

Įvadas

Viena iš stipriausių, o kartų ir silpniausių PHP pusių yra tai, kad išmokti programuoti yra labai lengva. Todėl PHP traukia daugelį žmonių, kurie nori išmokti juo programuoti. Nežiūrint į php lengvumą, išmokti naudoti šią kalbą teisingai ir efektyviai yra labai sunku.

Dažniausia problema: nepakankama praktika programuojant PHP. Nepatyrę programuotojai dažnai apsiima kurti sudėtingas web-technologijas, todėl dažnai paliekamos klaidos, kurių tikrai nepaliktų praktikos turintis php programuotojas.

Šioje straipsnio dalyje (iš trijų) bus pateiktos dažniausiai pasitaikančios klaidos tarp php programuotojų. Daromos klaidos gali būti paskirstytos į kelias kategorijas: nuo "nekritinių" iki "mirtinų". Kartu su klaidos aprašymu bus pateikiami jos sprendimo būdai, bei keletas gudrybių.

I dalis: pirmoje dalyje bus aptartos 7 "vaikiškos" klaidos (21-15, atvrikščia tvarka, pagal klaidos prioritetą). Šios klaidos didelių problemų nesukelia, bet gadina programos efektyvumą bei trikdo kodo skaitomumą (sunku prie projekto prisijungti kitam programuotojui).

II dalis: kitos septynios klaidos priskiriamos "kritinei" kategorijai. Tokių klaidų pasekmė - programos kodo vykdymo greičio kritimas, saugumo problemos, bei visiškas bardakas kode (programos kodas visiškai neperskaitomas).

III dalis: paskutinės septynios "mirtinos" klaidos. Tai koncepcinės klaidos, tokios kaip: žioplumo klaidos, nepakankamas įsigilinimas į projektą ar programos kodą.

21. neteisingas printf() funkcijos panaudojimas

funkcija printf() skirta formatuotų (sutvarkytų) duomenų išvedimui.

ja naudotis reikėtų tada, kai norima išvesti duomenis su "paslankiu kableliu" ir tam tikru tikslumu, arba kitose situacijose, kai reikia pakeisti išvedamų duomenų tipą.

žemiau pateikiamas teisingas pavyzdys, kada reiktų naudotis printf() funkcija. Šiuo atveju pavyzdys parodo, kaip išvedama PI reikšmė norimu formatu:


<?php
printf ("Skaičius PI: %.2f\n<br>\n", M_PI);
printf ("Taip pat skaičius PI: %.3f\n<br>\n", M_PI);
printf ("Irgi skaičius PI: %.4f\n<br>\n", M_PI);
?>


<?php
$name = 'Nikolajus Krauklis';
$job = 'Programuotojas';
$company = 'Alternatyvus Valdymas';
$email = '[email protected]';

printf ("Mano vardas: %s\n<br>\n
Aš dirbu: %s, %s\n<br>\n
Mano el. pašto adresas: %s\n<br>\n",
$name, $job, $company, $email);
?>

Sekančiame pavyzdyje: teisingas print() funkcijos panaudojimas:

<?php
print "Mano vardas: $name\n
Aš dirbu: $job, $company\n
Mano el. pašto adresas: $email\n";
?>

funkcijos print() naudojimas vietoj printf() naudingas štai kodėl:

funkcija printf() formatuoja eilutę, todėl jos atilikimo laikas žymiai ilgesnis nei naudojant funkcijas print() ar echo()

reikia pripažinti, kad funkcijos printf() kodas yra žymiai neįskaitomesnis nei print() ar echo() funkcijų kodai. Tuo labiau, kad reikia žinoti printf() funkcijos sintaksę: %s - eilutės tipo kintamojo įstatymas, %d - dešimtainio skaičiaus įstatymas ir kiti argumentai

eilutės formatavimas iš gautos funkcijos reikšmės panaudojus printf()

tai dar viena dažnai pasitaikanti klaida naudojant printf(). Štai jums ir pavyzdys:

<?php
printf ("Rasta: %d įrašų su jūsų paieškos žodžiu: %s.",
count($result), $search_term);
?>

Kai vietoj to galima naudoti funkcija print() ar echo():

<?php
print "Rasta: ". count($result) .
" įrašų su jūsų paieškos žodžiu: $search_term.";
?>

operatorius "." leidžia sujungti kelis kintamuosius į vieną eilutės tipą. Taip mes su funkcija print()/echo() apėjom žymiai lėtesnę funkciją printf().

20. netaisyklingas semantikos supratimas bei pritaikymas

dauguma vartotojų programuoja PHP iš tiesų nesuprasdami šios kalbos emės/privalumų. Viena iš klaidų - tai PHP sintaksės neskirimas nuo PHP semantikos:

PHP sintaksė: tai taisyklių rinkinys kaip aprašyti kalbos elementus. Pavyzdžiui kaip mes aprašome kintamąjį? Tiesiog prieš kintamojo pavadinimą dedame ženklą "$". Kaip aprašome funkciją? Prieš funkcijos pavadinimą rašome "function" ir funkcijos turinį apskliaudžiame laužtiniais skliaustais "{ }" ir t.t.

PHP semantika: tai taisyklių rinkinys kaip naudoti sintaksę. Pavyzdžiui pasiimame funkciją su dviem argumentais - php sintaksė, o tie argumentai ateinantys funkcijai turėtų būti eilutės "string" tipo - tai semantika.

Pastebėjote, kad išryškinome žodį "turėtų". Programavimo kalbose, tokiose kaip Java, C (ar kitos), NĖRA žodžio turėtų, kadangi jose visų kintamųjų tipai yra griežtai apibrėžti, kompiliatorius praneša klaidą apie netinkamą kintamojo tipo panaudojimą (integer tipo kintamajam negalime priskirti string tipo kintamąjo ir t.t.)

PHP kalboje nėra kintamųjų aprašymo, todėl php programuotojui suteikiama daugiau laisvės rašant kodą. Bet kaip bebūtų keista dažnai atsiranda klaidos dėl netaisyklingos semantikos naudojimo PHP funkcijose.

Pavyzdžiui paimame išeities kodo gabalą, kuriame yra atidaromas failas ir perskaitomas jame esantis turinys:

<?php
$fp = @fopen ('failas.txt', 'r')
or die ('Negalime atidaryti failo failas.txt');

while ($line = @fgets ("$fp", 1024)) // Šioje vietoje klaida
{
print $line;
}

@fclose ("$fp") // Bei šioje vietoje klaida
or die ('Negalime uždaryti failo failas.txt');
?>

Pateiktas kodas jums gražins klaidą:

"Warning: Supplied argument is not a valid File-Handle resource in C:\web\localhost\tst.php on line 4."

Tai įvyko dėl to, kad kintamasis $fp funkcijoms buvo perduotas dvigubose kabutėse, o tai reiškia, kad pateikiamas kintamasis funkcijai bus eilutės tipo "string". O funkcija fopen(), pirmojo kintamojo laukia nuorodos į failo išteklį (file handler resource), kai mes padavėme eilutės tipo kintamąjį, php interpretatorius gražino klaidą apie netaisiklingą semantiką.

Norint ištaisyti turimą problemą, užtenka pašalinti dvigubas kabutes aplink kintamąjį. Štai taip:

<?php
$fp = @fopen ('failas.txt', 'r')
or die ('Negalime atidaryti failo failas.txt');

while ($line = @fgets ($fp, 1024))
{
print $line;
}

@fclose ($fp)
or die ('Negalime uždaryti failo failas.txt');
?>

Kaip išvengti panašių semantikos klaidų?

duotame pavyzdyje PHP gražina sugeneruotą klaidą. Bet PHP, programuotojui duoda daugiau laisvės nei kitos tradicinės programavimo kalbos. Joje teoriškai galima parašyti taisyklingą kodą (kodas, kuris nemes klaidos), neteisingai panaudojus php semantiką.

Būkite atsargūs žaizdami su php semantika. Gali pasitaikyti klaidų, kurios dažnai sunkiai "pagaunamos" php išeities tekste (source). Jei jūs vis dėlto nusprendėte paeksperementuoti su php semantika, jums reikia žinoti tris pagrindinius dalykus:

Duomenų tipai: vykdant php kodą, kiekvienas kintamasis bet kuriuo momentu turi tam tikrą tipą. Tas kintamojo tipas bet kuriuo metu gali kisti priklausomai nuo jūsų kodo. Esmė tame, kad kintamasis vykdant kodą visada turi savo tipą. PHP turi 7 pagrindinius kintamųju tipus: boolean, resource, integer, double, string, array ir object.

Kintamojo matomumas (eng.: variable scope): php kintamieji turi "matomumo laukus" kaip ir kitose programavimo kalbose, bei gyvavimo laiką. Nepakankamas supratimas apie kintamųjų matomumą gali iškelti kai kurias klaidas. (Matomumas - funkcijoje aprašytas kintamasis bus matomas tik esamai funkcijai, kintamasis baigus funkcijai darbą yra naikinamas ir t.t.)

php.ini: parašius kodą reikia suprasti, kad nevisi kodo varotojai turi tas pačias sąlygas: tą pačia php ver., bei tokią pačią php konfiguraciją. Todėl būtina tikrinti, ar jūsų kodas dirba būtent po sistema tinkama jums. Pavyzdžiui: tikrinti, ar jums reikalingi extension'ai yra užkrauti ir t.t.

19. nepakankamas arba per didelis php išeities kodo komentavimas

blogai komentuotas php išeities tekstas (source) tik parodo programuotojo egoistiškumą. Bandymas tokį kodą analizuoti gali baigtis galvos skausmais. Ir prie analizavimo galite prasėdėti ne vieną valandą, bet dieną, savaitę... Dauguma programuotojų mano, kad gerai pakomentuotas išeities tekstas yra gerai, bet patys dažniausiai jo nekomentuoja.

be abejo reiktų saugotis ir per daug komentarų. tai taip pat maišo skaityti išeities tekstą. Štai per didelio komentarų kiekio pavyzdys:

<?php // PHP kodo pradžia
$age = 18; // užsetiname kintamąjį age bei priskiriame jam 18
$age++; // padidiname age kintamąjį vienetu

// išvedame vartotojui pradinį tekstą
print "Dabar jūs esate 19 metų, o buvote:";
print "\n<br>\n<br>\n";

// Ciklas kuris išveda visus prieš
// tai buvusius metus
for ($idx = 0; $idx < $age; $idx++)
{
// išvedame esamą metą :)
print "$idx metų\n<br>\n";
}
// PHP kodo pabaiga
?>

Ir visdėlto, kur yra aukso vidurys?

Taigi, kiek komentarų reikėtu rašyti savo programos kode? Tai priklauso nuo daugelio kriterijų: nuo jūsų projekto laiko, nuo jūsų įmonės politikos/pažiūrų, projekto sudėtingumo ir t.t. Bet štai šiuos kelis dalykus reikia žinoti bet kokiu atveju:

prieš funkcijos pradžią visada komentuokite kam duota funkcija skirta

rašykite komentarus vietose, kur kodas sudėtingas ir nesate įsitikinęs ar jis veiks gerai

stenkitės nenaudoti komentarų su '#', naudokite: '/* */', '//'.

Sekantys pavyzdys rodo gerą komentarų stilių:

<?php
// Random_Numbers.lib
// Generuoja skirtingus tipus random skaičiaus.
mt_srand((double)microtime()*1000000);

//
// mixed random_element(array elements[, array weights])
// Gražina atsitiktinį masyvo elementą.
//

function random_element ($elements, $weights=array())
{

// Kad algoritmas būtų teisingas masyvas elementų
// skaičius turi atitikti masyvo su atsitikiniais
// skaičiais elementų
if (count ($weights) == count ($elements)) {
foreach ($elements as $element)
{
foreach ($weights as $idx)
{
// Pastaba: mes nenaudojame $idx kadangi
// mums nereikalingi masyvo $weights elementai.
$randomAr[] = $element;
}
}
} else {
$randomAr = $elements;
}

$random_element = mt_rand (0, count ($randomAr)-1);
return $randomAr[ $random_element ];
}
?>

18. per daug laikinų kintamųjų - per didelis kodo atlikimo laikas

dažnai programuotojai neteisingai naudojasi laikinais kintamaisiai. Tai galima suprasti iš štai tokių ir panašių išeities tekstų:

<?php
$tmp = date ("F d, h:i a"); /* turėsime: January 3, 2:30 pm */
print $tmp;
?>

Kam šioje vietoje naudojamas laikinas kintamasis? Čia jis visiškai nereikalingas:

<?php
print date ("F d, h:i a");
?>

Deja, dauguma programuotojų negali atsikratyti šio kvailo įpročio. Laikinųjų kintamųjų vartojimas lėtina programos atlikimą. Jie padidina atlikimo laiką praktiškai ketvirčiu.

Dar viena priežastis, dėl kurios reiktų stengtis naudoti kuo mažiau laikinųjų kintamųjų, - tai tvarkingas kodas, bei išeities teksto skaitomumas. Pabandykite sulyginti aukščiau pateiktus pavyzdžius, ir pamąstykite, kuris iš jų jums yra lengviau skaitomas?

Kada laikinieji kintamieji pateisina save?

Laikinieji kintamieji dažnai leidžia supaprastinti kai kuriuos veiksmus, kodo eilutę ar funkciją.
Štai pavyzdys kuriame nenaudojami laikinieji kintamieji:

<?php
// string reverse_characters(string str)
// Apverčia eilutės tipo kintamąjį kitu galu
function reverse_characters ($str)
{
return implode ("", array_reverse (preg_split("//", $str)));
}
?>

Šis kodas yra sunkiai skaitomas, kadangi funkcijai implode yra perduodamas kitos funkcijos: array_reverse() rezultatas. Duotoje situacijoje kodo skaitomumą galima pataisyti pasinaudojus laikinais kintamaisiais:

<?php

// string reverse_characters(string str)
// Apverčia eilutės tipo kintamąjį kitu galu
function reverse_characters ($str)
{
$characters = preg_split ("//", $str);
$characters = array_reverse ($characters);

return implode ("", $characters);
}
?>

Auksinė taisyklė

jei jūs nesate įsitikinęs ar įvesti laikinąjį kintamąjį ar ne, sau turite užduoti du klausimus:

ar sukurtas laikinas kintamasis bus naudojamas bent jau du kartus jūsų kode?

ar tikrai pagerės jūsų kodo skaitomumas įvedus šį laikinąjį kintamąjį

Jei nors į vieną iš šių klausimų jūs atsakysite "Taip", tada drąsiai galite įsivesti laikinąjį kintamąjį, kitu atveju jūs apseisite be jo.

17. perrašome standartines funkcijas

kai kas rekomenduoja perrašyti PHP funkcijų vardus, kad "Visual Basic'o" programuotojai galėtų lengviau pereiti prie PHP:

<?php
function len ($str)
{
return strlen ($str);
}
?>

taip pat dažnai pasitaiko pasiūlymai pervadinti PHP funkcijas labiau trumpesniais ir dažniau pasitaikančiais kitose programavimo kalbose vardais.

Egzistuoja mažiausiai dvi priežastys, kodėl taip nereikia daryti. Visų pirma - pats svarbiausias dalykas, tai, kad po tokio pervadinimo mes gausime blogiau skaitomą išeities kodą ( prisiminkime ASM'ą ). Beto, daugiausiai programuotojai jūsų koduose pamatys funkcijas darančias tą patį, ką ir jau esamos php funkcijos.
Ir antra - tai labai prailgina programos atlikimo laiką.

Naudokitės standartinėmis PHP funkcijomis!

Dažnai tam yra sunku atsispirti, juk programuotojas negali žinoti viso php funkcijų rinkinio mintinai. Todėl manydamas, kad tokios funkcijos PHP tiesiog neturi, programuotojas ją pasidaro pats. Patikėkite, jūs funkcijos, kuri daro tą patį ką ir PHP funkcija, geresnės neparašysite,.

Geriausiai po ranka turėti kokį nors PHP pagalbininką po ranka: ar žodyną (manual'ą - ar pdf, ar html ar chm formatu), ir prieš tai, kai pradėsite rašyti funkciją pagalvoję, kad tokios PHP neturi, patikrinkite ar jos tikrai nėra!

Bet reikia pastebėti, kad retkarčiais pasitaiko išeities tekstų su funkcijomis, kurios buvo parašytos dar prieš tam tikros funkcijos atsiradimą PHP kalboje. Tai nereiškia kad programuotojas buvo neįžvalgus. Ir tikrai nereikia pulti ir perrašyti kodą su nauja funkcija.

16. klientinė kodo dalis maišoma su serveryje atliekamu kodu

dažnai programuotojai siūlo klientinę svetainės dalį (HTML) apjungti su serverine svetainės dalimi (PHP). Tai dar senais laikais, kai tik atsirado PHP, buvo vienas iš pliusų, kad php kodą įstatyti galima bet kokioje html vietoje. Bet ar tai tikrai taip gerai?

Svetainėms kurios yra mažos, tai galbūt yra gerai. Bet kai jūsų puslapis ims augti, jūs susidursite su problema redaguojant kodą bei jį papildant. Toks programavimo stilius priveda prie netvarkingo ir "nepaklusnaus" išeities teksto.

API funkcijos

jeigu jūs nusprendėte nemaišyti HTML ir PHP kodo, tai yra keli variantai kaip tai galima padaryti. Vienas iš paprastesnių būdų, tai kurti funkcijas kurios atlieka tam tikrus veiksmus ir gražina reikiamą rezultatą ir šias funkcijas tiesiog iškvietinėti vietose, kur jums reikia to rezultato:

index.php // puslapio kodas

<?php include_once ("site.lib"); ?>

<html>
<head>
<title>
<?php print_header (); ?>

</title>
</head>
<body>
<h1>
<?php print_header (); ?>

</h1>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="25%">

<?php print_links (); ?>

</td>
<td>

<?php print_body (); ?>

</td>
</tr>
</table>
</body>
</html>

site.lib // funkcijų rinkinys

<?php

$dbh = mysql_connect ("localhost", "sh", "pass")
or die (sprintf ("Cannot connect to MySQL [%s]: %s",
mysql_errno (), mysql_error ()));
@mysql_select_db ("MainSite")
or die (sprintf ("Cannot select database [%s]: %s",
mysql_errno (), mysql_error ()));

$sth = @mysql_query ("SELECT * FROM site", $dbh)
or die (sprintf ("Cannot execute query [%s]: %s",
mysql_errno (), mysql_error ()));

$site_info = mysql_fetch_object ($sth);

function print_header ()
{
global $site_info;
print $site_info->header;
}

function print_body ()
{
global $site_info;
print nl2br ($site_info->body);
}

function print_links ()
{
global $site_info;

$links = explode ("\n", $site_info->links);
$names = explode ("\n", $site_info->link_names);

for ($i = 0; $i < count ($links); $i++)
{
print "\t\t\t
<a href=\"$links[$i]\">$names[$i]</a>
\n<br>\n";
}
}
?>

Kaip matote šis kodas lengviau skaitomas nei būtų sukeltus viską į vieną vietą.

Šio būdo pliusai:

praktiškai švarus išeities kodas

greitas kodas

Minusai:


ne ant tiek gerai kaip šablonų sistema

vis dėlto modifikuoti išeities tekstą turėtu šiek tiek išmanantis php žmogus

Šablonų sistema

šablonų sistema taip pat leidžia atskirti vartotojo dalį nuo serverinės pusės. HTML'e tam tikrose vietose įdedamas vartotojo tegas. Štai tokio šablono pavyzdys iš pukomuko template engine tutorial'o:

masyvo elementų vardai pridedami
per tašką prie handlo vardo:

<br>
<br>
var.id - {var.id}<br>
var.info - {var.info}<br>
var.sub.id - {var.sub.id}<br>
var.sub.info - {var.sub.info}<br>
<br>
atkreipiu dėmesį, kad tokio handlo
kaip <b>var</b> neatsirado.

Šablonų klasių yra visokių: FastTemplate, SmartyTemplate, QuickTemplate, phemplate ir t.t.

Apie phemplate galite paskaityti štai čia: http://beta.php.lt/render/page,inside;menuitem,31;aid,40

15. pasenusios php sintaksės naudojimas

dauguma programuotojų vis dar naudoja seną PHP sintaksę. Pavyzdžiui išeities kodas parašytas ant PHP2/FI iki šiol kai kur naudojamas PHP.

pasenusios sintaksės bei pasenusių funkcijų naudojimas didina php kodo atlikimo laiką, todėl reikia stengtis jų nenaudoti. Dažnai kiti programuotojai yra nesusipažinę su sena sintakse, todėl toks išeities tekstas jiems pasirodys baisus ir neįskaitomas.

Štai pavyzdys:

<?php

// Bloga/Pasenusi sintaksė

while (1):
print "5";
if ($idx++ == 5):
break;
endif;
endwhile;

// Geresnis sintaksės pavyzdys
// (kodas vis dar gali būti optimizuotas)

while (1)
{
print "5";
if ($idx++ == 5) {
break;
}
}

?>

Kodėl gi reikia programuoti nauju standartu? Štai priežastys, kodėl taip turi būti:

sena sintaksė nėra populiari tar php išeities tekstų, todėl naujokas pamatęs du variantus susimėtys, ir gali būti, kad seks blogu keliu

sena sintaksė skiriasi nuo kitų programavimo kalbų sintaksės, todėl "nušokęs" programuotojas nuo kitos programavimo kalbos bus pasimetęs/nepatenkintas.

bet pats svarbiausias argumentas yra tas, kad bet kuriuo metu naujoje PHP versijoje gali būti išmestas senos PHP sintaksės palaikymas!!!

Reziumė

šiame straipsnyje mes apžvelgėme pirmas septynias iš 21 dažniausiai sutinkamų klaidų tarp php programuotojų. Jų reikėtų vengti.

---
[^] Atgal
[«] Skaitykla

* * Gen. time: 0.1325
* © xneox.com