Kódolás, módszerek, optimalizáció első rész: tervezés, függvények


Mint programozó, egy idő után biztos találkozni fogunk az optimalizáció fogalmával. Ennek rengeteg szintje és módja létezik, de elsősorban a sebesség növelése, ill. a terhelés csökkentése (kevesebb memória használat, kevesebb kód stb..) az elsődleges cél.

Kisebb szkriptek esetében nincs igazán értelme erről beszélni, még akkor sem, ha a programunk 100 000 felhasználó kérését fogadja és dolgozza fel, hiszen minnél kisebb egy program, azt annál nehezebb “jól” optimalizálni. Természetesen nem muszáj a “relatíven” lassú scriptnyelveket igénybe vennünk, mikor szerverooldalon programozunk, hiszen ezt ugyanúgy megtehetjük Java, Visual Basic, vagy akár Assembly segítségével is.
A php nagy előnye, hogy elég nagy szabadságot biztosít a programozónak. Nem szükséges előre deklarálnunk a változóinkat, függvényeket, nem kell azzal foglalkoznunk, mi történik velük később, és nem kell futásidejű problémákkal bajlódnunk, hiszen ezt a php értelmező mind megteszi nekünk (legalábbis megpróbálja). Most 5 pontban írok arról, hogy általában mire érdemes figyelnünk php programozás közben, a gyakorlati oldalról nézve.

1. tervezés

Én személy szerint nem vagyok a tervezés híve. Ezzel talán sokan így vannak, hiszen úgy tűnhet, felesleges időpazarlás, amikor rögtön el is kezhetjük a program kódolásást, a többiek pedig most kinevetnek ezért, vagy talán azzal jönnek, hogy a “profik” így meg úgy.(még szerencse hogy nem vagyok profi)
Ha nagyobb munkán dolgozunk, nem árt, ha fejben magunk előtt látjuk, mit is csinál a program, vagy mi mit is várunk el tőle. Ha elakadunk, még mindig elővehetjük a tollat és a papírt, vagy a képzeletünket. De vajon melyik a jobb? Ha leírjuk egy papírra, mit akarunk, majd egyszerre lekódoljuk, vagy egy üres programból kiindulva, fokozatosan jutunk el a célig?

Nézzünk egy egyszerű függvényt:

1
2
3
4
5
6
7
<?php
function egyszeru() 
 {
 echo "Ezt most kiírom";
 }
egyszeru();
?>
1
2
3
4
5
6
7
<?php
function egyszeru($szoveg) 
 {
 echo $szoveg;
 }
egyszeru("Ezt most kiírom");
?>
1
2
3
4
5
6
7
<?php
function egyszeru($szoveg,$szin) 
 {
 echo "<p style=color:$szin>".$szoveg."</p>";
 }
egyszeru("Ezt most kiírom","red");
?>

Vagy egyszerű tervezéssel:

egyszeru(Szoveg,Szin);
Kiírja a megadott szöveget(Szoveg) a megadott színnel(Szin)

Az nyilvánvaló, hogyha előre tervezünk (mondjuk rosszul :), a hibajavítás néha lehetetlenné válik, hiszen nem tudhatjuk, hol és mit rontottunk el, sőt akár maga a logika amit követtünk egy-az egyben téves lehet. Ha folyamatosan bővítjük a kódot, a problémák ugyan folyamatosan érkeznek, viszont egy adott bővítés után általában tudhatjuk, hogy (valószínüleg) az aktuális bővítés miatt generál hibát a programunk. Én ez utóbbi miatt részesítem előnyben egy adott program folyamatos bővítését. Sok file használata mellett nem árt leírnunk (pl. gráfokkal, vagyis rajzoljunk), hogy melyik php file mit használ fel, és ez különösen igaz, ha a kód szét van darabolva. Pl. van egy ilyen listánk:

  • main.php
  • tartalom.php
  • kepek.php
  • linkek.php
  • config/config.php
  • config/funcs.php
  • config/sql.php

Melyik file függ melyiktől? Mondjuk a config.php-t mindegyik igényli? Vagy az sql.php-t? Ha sok include-ot használunk, célszerű azokat már a file elején beemelni, amikre biztos szükségünk lesz, míg ami egy adott feltétel mellet fut majd le, azt csak akkor és ott. Ezzel ugyanis jelentősen megkönnyítjük a php értelmező dolgát, hiszen a gyakran több ezer soros php file-ok beszúrása jelentős
számítási teljesítménybe kerül. Tehát a fenti példában, mondjuk ha a kepek.php képeket listáz ki egy sql szerver táblája alapján, de csak akkor, ha a felhasználó rákattint egy linkre:

kepek.php:

1
2
3
4
5
6
7
8
9
<?php
include("config/config.php");
if (isset($_GET['kepek'])) 
 {
include("config/sql.php");
//Sql parancsok
 }
//
?>

2. függvények

Valószínüleg a függvények a leghasznosabb szerkezetek a programozásban, ahogy a matematikában is, bár ez debilen hangzik, hiszen maga a programozás is függvényekre (pontosabban relációkra) épül. Absztrakt szinten láthatjuk, hogy pl. az értékadás, a vezérlési szerkezetek (if stb..) mind relációk. Ma sokat (vagy már keveset) hallani az oop-ről, a php 5 legnagyobb újdonságai is az objektumokkal kapcsolatosak. Amikor egy osztályra gondolunk, lényegében adatok egy halmazát képzeljük el, amiken összetartozó függvények műveleteket végeznek. Sok php-vel foglalkozó könyvben olvastam, hogy ahol csak tudunk, használjunk “burkoló” osztályokat.

Ez utóbbi fogalomra most nem térek ki, sok helyen utána lehet olvasni, és ahogy látom, nálunk még nem igazán terjedt el a php programozók között az osztályok használata (persze nem a profik szintjén).
Meg kell jegyezni, ez nem baj. Osztályokat tényleg csak ott érdemes alkalmazni, ahol tudjuk, hasonló műveleteket fogunk máshol is végezni, és nem szeretnénk függvényeinket és adatainkat újra kidolgozni. Néhány példa: form-ok ellenőrzése, adatbázisok elérése, file beolvasás/írás, adatellenőrzés, munkamenet kezelés, html elemek kiírása (táblázat,select, inputok stb..), és hasonlók.

Mint láthatjuk, egy php alapú oldal nagy részét újra tudjuk hasznosítani. Ehhez segítségünkre vannak az olyan fogalmak, mint öröklés, zártság, absztrakt osztályok.
De visszatérve az osztályok, és (talán) az egész modern programozás alapjára: egy függvény legnagyobb előnye, hogy mi hívhatjuk meg, és “visszaad” egy értéket.
Lényegében a függvényt is hívhatjuk vezérlési szerkezetnek, hiszen az, hogy egy függvényt deklarálunk, nem jelenti azt, hogy meg is hívjuk, tehát lényegében
feltételhez kötjük a végrehajtást.

Nézzük meg egy egyszerű pédával, szeretnénk egy személy testtömegindexét kiszámolni, majd megmondani, hogy mennyire tér el az ideálistól:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
$suly=75;
$magassag=180;
if ($suly<1 or $suly>500 or !(is_numeric($suly))) 
 {
 echo "A súlynak 1 és 500 kg között kell lennie";
 }
 else 
 {
  if ($magassag<10 or $magassag>300 or (!is_numeric($magassag))) 
  {
  echo "A magasságnak 10 és 300 cm között kell lennie";
  }
  else 
  {
   $magassag=$magassag/100;
   $index=$suly/($magassag*$magassag);
   $index=intval($index);
   if ($index<=18) 
    {
    echo "Ön túl sovány, a BMI indexe: ".$index;
    }
   if ($index>18 and $index<=20) 
    {
     echo "Ön sovány, a BMI indexe: ".$index;
    }
   if ($index>20 and $index<=25) 
    {
     echo "Az ön testsúlya ideális, a BMI indexe: ".$index;
    }
   if ($index>25 and $index<=30) 
    {
    echo "Ön enyhén túlsúlyos, a BMI indexe: ".$index;
    }
   if ($index>30) 
    {
    echo "Ön túlsúlyos, a BMI indexe: ".$index;
    }
  }
 }
?>

Mi is itt a gond?

Rögtön látszik, hogy a program belefullad az if-ekbe és else-ekbe, attól függetlenül, hogy lényegében egy egyszerű számítási feladatot végeztünk, némi adatellenőrzéssel és kiírással.
Egy több ezer soros kód esetében már átláthatatlan lenne maga a program, és ha bővíteni akarnánk, akkor kezhetnénk megint if-ekkel bajlódni. Ráadásul ha több helyen használjuk, és át szeretnénk írni valamit, azt minden egyes helyen meg kell tennünk.
Eddig ezt bármelyik programozás tankönyvben olvashattuk, de sok helyen nincs megemlítve, hogy maga a függvény is zárt szerkezetet alkot. A fenti programot például szétválaszhtatjuk 3 függvényre, egy végzi az adatok ellenőrzését, egy maga a számolást visszaadvaa a kiírandó szöveget, az utolsó pedig ki is írja:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
//Adatellenőrzés
function bmi_index_ellenor($suly,$magassag) 
 {
  if (!is_numeric($suly)) {$uzenet="A súly csak szám lehet";return $uzenet;}
  if (!is_numeric($magassag)) {$uzenet="A magasság csak szám lehet";return $uzenet;}
  switch ($suly) 
   {
   case $suly<2: $uzenet="A súly nem lehet kisebb, mint 2 kg";return $uzenet;break;
   case $suly>500:$uzenet="A súly nem lehet nagyobb mint 500 kg";return $uzenet;break;
   }
  switch ($magassag) 
   {
   case $magassag<10: $uzenet="A magasság nem lehet kisebb, mint 10 cm";return $uzenet;break;
   case $magassag>300: $uzenet="A magasság nem lehet nagyobb, mint 300 cm";return $uzenet;break;
   }
  return 1;
 }
//BMI index kiszámolása, eredmény összefűzése
function bmi_index_szamol ($suly,$magassag) 
 {
  $magassag=$magassag/100;
  $index=$suly/($magassag*$magassag);
  $index=intval($index);
  switch ($index) 
  {
   case $index<=18: $uzenet="Ön túl sovány,";break;
   case $index>18 and $index<=20: $uzenet="Ön sovány,";break;
   case $index>20 and $index<=25: $uzenet="Ön normális testsúlyú,";break;
   case $index>25 and $index<=30: $uzenet="Ön túlsúlyos,";break;
   case $index>30:$uzenet="Ön kórosan túlsúlyos";break;
   default:return;
  }
 $uzenet.=" a BMI indexe: ".$index;
 return $uzenet;
 }
 
//Üzenet megjelenítése
function drop_uzenet($uzenet) 
 {
  if (empty($uzenet)) {return;}
  if (is_array($uzenet)) 
   {
   foreach ($uzenet as $mess) 
    {
    echo $mess."<br>";
    }
   }
   else {
  echo $uzenet;
  }
 }
 
$suly=75;
$magassag=180;
$uzenet=bmi_index_ellenor($suly,$magassag);
if ($uzenet==1) 
 {
  $eredmeny=bmi_index_szamol($suly,$magassag);
  drop_uzenet($eredmeny);
 }
 else {
  $uzenet="Hiba: ".$uzenet;
  drop_uzenet($uzenet);
  }
?>

De miért is jobb ez utóbbi? Hiszen több lett a kód (40 helyett 65 sor), és ráadásul
automatikusan nem is fut le semmi (vagyis a függvényt meg kell hívni). Rögtön látszik azonban, hogy több vezérlési szerkezet (case-ek) használata mellett
is átláthatóbb lett maga a kód (remélem). SZétválasztottuk az adatellenőrzést,az eredmény kiszámolását, és annak megjelenítését. utólag sokkal könnyebb lesz a hibakeresés is, hiszen a függvények között mindig könnyen behatárolhatjuk, hogy melyikben van a hiba. Részletesebb hibaüzeneteket adhatunk a felhasználónak. Ha valamelyik részt ki szeretnénk iktatni, azt egyszerűen nem hívjuk meg.
A függvényekben mégis az a legszebb, hogy bármikor kiléphetünk belőlük. Nézzünk meg egy egyszerű jogosultság-kezelést. Az alábbi programban nem szeretnénk, hogy
a felhasználók törölhessenek és módosíthassanak admin és felhasználói adatokat, míg az adminoknak ezt megengednénk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
function modosito_user() 
 {
$csoport=$_SESSION['user']['csoport'];//Felhasználók csoportja
switch ($csoport) 
 {
case 'admin':$mod_user=true;
             break;
case 'user' :$mod_user=false;
             break;
default:return;
}
if (!$mod_user) {return;}
//Ide jöhet a felhasználó módosító rész, esetleg további ellenőrzéssel
}
?>

Ha illetéktelen lép ide be (pl. a user csoportba sorolt ember), akkor nem fog látni semmit. Ennek párjára csinálhatunk egy modosito_admin függvényt is, hasonló jogosultság-kezeléssel.

A függvények legfőbb célja persze az általánosítás. Ahol csak tehetjük, próbáljunk meg absztart függvényeket írni, vagyis olyanokat, amik kevésbé függenek statikus adatainktól.
Pl. a következő függvény teljesen értelmetlenül dolgozik, ilyenekre ne is írjunk soha függvényeket:

1
2
3
4
5
6
7
<?php
function szorzas() 
 {
 $szam=12*12;
 echo $szam;
}
?>

Ehelyett inkább (és ha már ragaszkodunk a 12-höz):

1
2
3
4
5
6
7
<?php
function szorzas($szam = 12) 
 {
 $szorzat=$szam*$szam;
 echo $szorzat;
}
?>

Ez természetesen kicsit túl egyszerű példa, de talán érthető.
Mivel php-ben nincsenek pl. a Pascalhoz hasonló eljárások, használhatunk a fenti (elsőhöz) hasonló szerkezeteket is, de én általában csak ott használom, amikor valamit részekre kell bontani, és nincsen adatfüggőség (tehát pl. nem függ az eljárás egy számtól). Ha az elsőhöz hasonló függvényünk van (tehát mindig ugyanazt csinálja ugyanazzal az adattal), akkor érdemes osztályba szervezni a függvény:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class mysql_kapocs 
 {
 var $szerver = "localhost";
 var $username = "admin";
 var $password = "123";
 var $state;
 //Kapcsolódás
 function connect_sql() {
 $sql=mysql_connect($this->szerver,$this->username,$this->password);
 if ($sql)  {
  $this->state=true;
  return $sql;
  }
 }
}
?>

Természetesen mindenkinek magának kell kialakítania azokat a módszereket, amikkel dolgozni fog, hiszen mindezt amit leírtam fent, meg lehet másképpen is (sokféleképpen) oldani, és nyilván létezik olyan módszer, ami teljesen kódkímélő, és kevés munkával sokkal többet ad vissza a dolgozónak. Ha tudsz ilyenről, oszd meg velem.:)
A következőkben a vezérlési szerkezetekről és a kódolási stílusról, szervezésről lesz szó.

BL

Kapcsolódó bejegyzések:
  • Ezt a kis kódrészletet azért osztom meg, mert sok javascriptes megoldást láttam már a dátum kiíratására. Alapból nekem nem tetszett, ahogy a php kiírja a date fü …

  • Ahogy belépek egy magyar nyelvű fórumba ahol webszerkesztés téma is van, olyan nincs, hogy ne találjak olyan kérdést, hogy “Keresés, hogyan?”. Most erre talász i …

  • A következőkben egy olyan, általam írt PHP-s függvényt szeretnék bemutatni, amellyel könnyedén és egyszerűen készíthetünk magunknak olyan oldalt, amely támogatja …

  • Még egy oldalon sem találkoztam egy igazából nem túl nagy munkával megoldható ötlettel: ha már PHP alapú dinamikus oldalt készítünk, akkor a design is legyen din …

  • Honlapkészítés során, ha a hagyományos módon – statikus HTML fájlokat gyártva – állsz neki a munkának, előbb vagy utóbb belefutsz abba a problémába, hogy elég ma …

A cikket beküldte: BL (http://webinform.hu)

Szólj hozzá
a Kódolás, módszerek, optimalizáció első rész: tervezés, függvények c. bejegyzéshez

- Engedélyezett HTML elemek: <a> <em> <strong> <ul> <ol> <li>
- Forráskód beküldéséhez tedd a kódot ezek közé: <pre lang="php" line="1">Kódrészlet helye itt</pre>