Home > Laboratorium, Programowanie > If…else czy return?

If…else czy return?

Trudno wymyślić sensowny tytuł dla zagadnienia które chcę opisać. Zawsze zastanawiało mnie czy pisząc w PHP funkcję która początkowo przeprowadza walidację przekazanych argumentów, stosować konstrukcję typu:

function nazwa($argument)
{
  if (warunek)
  {
    return FALSE;
  }
  ... ciało funkcji
}

…czy też:

function nazwa($argument)
{
  if (warunek)
  {
    return FALSE;
  }
  else
  {
    ... ciało funkcji
  }
}

Intuicyjnie może się wydawać że pierwszy metoda będzie działać szybciej, gdyż po spełnieniu warunku wychodzimy od razu z funkcji – parser nie musi przetwarzać reszty kodu. Z kolei w drugiej, mimo iż to co znajduje się w bloku else się nie wykona i tak musi zostać przeczytane przez PHP. Jak jest w rzeczywistości? Sprawdźmy to!

Pierwsza konstrukcja, w której po spełnieniu warunku wykluczającego dalsze przetwarzanie, od razu zwracamy wartość jest na pewno bardziej przejrzysta. Nie musimy ciągnąć za sobą nawiasu kończącego blok else przez całą resztę instrukcji. Drugi fragment kodu z kolei charakteryzuje się bardziej logiczniejszą strukturą – gdyż wyraźnie widzimy co się stanie w przypadku spełnienia warunku jak i jego odrzucenia.

Przejdźmy zatem do testów. Przygotowałem na tą okazję dwie, identyczne pod względem działania, funkcje korzystające z dwóch w/w konstrukcji zapisu:

function test_return($arg)
{
  if ($arg % 2 == 0)
  {
    return 0;
  }
  $arg = $arg*7+2;
  $a = $arg+3;
  $b = 1024;
  $arg = $a - $b*$arg;
  $arg =- 500;
  $arg *= 2;
  return $arg+256;
}

…oraz:

function test_else($arg)
{
  if ($arg % 2 == 0)
  {
    return 0;
  }
  else
  {
    $arg = $arg*7+2;
    $a = $arg+3;
    $b = 1024;
    $arg = $a - $b*$arg;
    $arg =- 500;
    $arg *= 2;
    return $arg+256;
  }
}

Jak można zauważyć, funkcje te nie mają zbytniego sensu, nie mniej ich głównym celem jest odrzucanie liczb parzystych a przetwarzanie jedynie nieparzystych.

Procedura testowa polegała na wykonaniu jednego miliona iteracji każdej z funkcji, podając kolejne liczby całkowite jako argument poczynając od 0.

for ($i = 0; $i < 1000000; $i++)
{
  test_return($i);
}

Wyniki jakie otrzymałem prezentują się następująco:

Nazwa funkcji Czas wykonania 1 000 000 iteracji
test_return() ~760ms
test_else() ~760ms

Jak widać, wyniki są identyczne. W praktyce występowały pewne wahania w zależności od wywołania skryptu, nie mniej średnio, obie funkcje wykonują się w tym samym czasie. Nie ma więc znaczenia jakiego typu konstrukcji użyjemy – najlepiej tej która bardziej nam w danej chwili odpowiada.

Dlaczego tak się dzieje? Przyczyny braku różnicy w czasie wykonania można dopatrywać się tym, iż parser PHP bądź co bądź musi przeczytać całą zawartość skryptu przed jego kompilacją i uruchomieniem. Skompilowany kod jednej i drugiej funkcji nie różni się zatem niczym, co mogło by w istotny sposób wpłynąć na czas jego wykonania.

  1. YanPL
    19 marca 2010 at 15:25 | #1

    Zabawne. W poszukiwaniu metody oszczędzającej czas obliczeniowy w iście semantycznym i drugorzędnym problemie zużyłeś swój własny czas, by następnie wykazać że żadna z konstrukcji nie oszczędza czasu obliczeniowego. Ciekaw jestem, czy wobec tego czas przeznaczony na zrobienie i opublikowanie tego testu kiedykolwiek się zwróci :P

  2. 19 marca 2010 at 18:56 | #2

    Ja nie poszukiwałem szybszej metody, tylko sprawdzałem która jest szybsza. Poza tym, czy się zwróci? Zaufaj mi, zwrócił się już w postaci odsłon -> reklam ;)

  1. Brak jeszcze trackbacków