Facebook
Twitter
Google+
Kommentare
0

Static-Variablen in Methoden

Seit paar Tagen optimiere und refactoriere ich eine Komponente die bereits vor einem Jahr von PHP4 auf PHP5 umgestellt und refactoriert wurde. Dabei bin ich auf viele lustige Codefragmente gestoßen. Eins hat bei mir für viel Aufmerksamkeit gesorgt. Und zwar: innerhalb einer Methode wurden Variablen die nur in dieser Methode verwendet werden als „static“ Deklariert. Hmmm…, was soll das den bitte? Ist es ein Feature? Wenn ja, wo ist der Verteil? So habe ich mich auf der Suche gemacht. Hier ein Beispiel aus der Komponente:

class SelectBox
{
    public function getTimeOptions()
    {
        static $hours, $mins, $options;

        $hours = range(0, 23, 1);
        $mins  = range(0, 45, 15);

        foreach ($hours as $hour)
        {
            foreach ($mins as $min)
            {
                $hour = ($hour == 0) ? '00' : $hour;
                $hour = (mb_strlen($hour) == 1) ? '0'.$hour : $hour;
                $min = ($min == 0) ? '00' : $min;

                $options[] = $hour.':'.$min;
            }
        }

      return $options;
    }
}

In den oben gezeigtem Beispiel ist es deutlich zu sehen, dass die alte Deklaration „global“ einfach durch „static“ ersetzt worden ist. Ob an diese Stelle richtig refactoriert worden ist, sei es mal hingestellt. Die Methode „getTimeOptions“ soll ein Array zurück liefern das alle Uhrzeiten zwischen 00 Uhr und 23 Uhr in 15 Minuten Schritte beinhaltet. Also, ein Array wie das hier:

Array
(
    [0] => 00:00
    [1] => 00:15
    [2] => 00:30
    [3] => 00:45
    [4] => 01:00
    [5] => 01:15
    [6] => 01:30
    [7] => 01:45
    [8] => 02:00
    [9] => 02:15
    [10] => 02:30
    [11] => 02:45
    [12] => 03:00
    [13] => 03:15
    [14] => 03:30
    [15] => 03:45
    [16] => 04:00
    ...
    ..
    .

Nun habe ich mich genau über die „static“ Deklaration informiert und erfahren, dass auch in der Programmierung eine Variable als ein Akkumulator verwendet werden kann. Man kann sie also aufladen und entladen. Ist also besonders gut geeignet um Zwischenergebnisse, innerhalb der Laufzeit eines Prozesses abzulegen. Solche Akkumulatoren sollen auch in Schleifen innerhalb von PHP selbst verwendet werden. Hmm…, das klingt spannend! Also eine Art Cache bzw. Zwischenspeicher. Kurzerhand habe ich die Klasse umgebaut. Hier die Klasse nach dem ersten Umbau:

class SelectBox
{
    public function getTimeOptions()
    {
        static $options;

        var_dump(empty($options));

        if (true === empty($options))
        {
            $hours = range(0, 23, 1);
            $mins  = range(0, 45, 15);

            foreach ($hours as $hour)
            {
                foreach ($mins as $min)
                {
                    $hour = ($hour == 0) ? '00' : $hour;
                    $hour = (mb_strlen($hour) == 1) ? '0'.$hour : $hour;
                    $min = ($min == 0) ? '00' : $min;

                    $options[] = $hour.':'.$min;
                }
            }
        }

        return $options;
    }

}

class CheckBox
extends SelectBox
{

}

Den Aufruf „var_dump(empty($options));“ habe ich absichtlich eingebaut um die Auswirkung von unseren Akkumulator deutlicher zu machen. Zudem habe ich die Klasse mit der „CheckBox“ Klasse erweitert. Einfach für testzwecke. Ich weiß ja nicht was mich erwartet. Hier der Test:

$selectBox = new SelectBox();
print 'Instance of SelectBox'.PHP_EOL;
print 'CALL 1:';$selectBox->getTimeOptions();
print 'CALL 2:';$selectBox->getTimeOptions();
print 'CALL 3:';$selectBox->getTimeOptions();
print '----------------------------'.PHP_EOL;

$selectBox = new SelectBox();
print 'Instance of SelectBox'.PHP_EOL;
print 'CALL 1:';$selectBox->getTimeOptions();
print 'CALL 2:';$selectBox->getTimeOptions();
print 'CALL 3:';$selectBox->getTimeOptions();
print '----------------------------'.PHP_EOL;

$checkBox = new CheckBox();
print 'Instance of CheckBox'.PHP_EOL;
print 'CALL 1:';$checkBox->getTimeOptions();
print 'CALL 2:';$checkBox->getTimeOptions();
print 'CALL 3:';$checkBox->getTimeOptions();
print '----------------------------'.PHP_EOL;

Hier die Ausgabe:

Instance of SelectBox
CALL 1:bool(true)
CALL 2:bool(false)
CALL 3:bool(false)
----------------------------
Instance of SelectBox
CALL 1:bool(false)
CALL 2:bool(false)
CALL 3:bool(false)
----------------------------
Instance of CheckBox
CALL 1:bool(true)
CALL 2:bool(false)
CALL 3:bool(false)
----------------------------

Das Ergebnis ist nicht verblüffend. Beim aller ersten Aufruf der Methode wird die Berechnung der Zeit-Optionen ausgeführt und in dem Akkumulator gespeichert. Bei jedem weiterem Aufruf der Methode wird direkt auf dem Akkumulator zugegriffen. Auch wenn die Instanz von SelectBox neu erzeugt wurde. Bei der Instanz von CheckBox, die SelectBox erweitert, müssen die Zeit-Optionen wiederum neu berechnet werden. Ein Vorteil hat das nur wenn man sicher ist, dass eine Berechnung lange dauert und dasselbe Ergebnis im gesamten Prozess zurück liefert. Den Einsatz von der „static“ Deklaration betrachte ich mit gemischten Gefühlen. Einerseits hat das nichts mehr in der Objekt-Orientierten-Programmierung zu suchen, andererseits kann es doch nützlich sein, wenn man genau weiß wie es eingesetzt werden kann.

Hier habe ich ein endgültiges refactoring vollzogen. Denn mir war wichtig, dass die Methode flexibler wird, und mit anderen Uhrzeit- und Minuten-Abstände arbeiten kann.

class SelectBox
{
    public function getTimeOptions(array $hours, array $mins)
    {
        static $options;

        if (true === empty($options))
        {
            foreach ($hours as $hour)
            {
                foreach ($mins as $min)
                {
                    $hour = (mb_strlen($hour) == 1) ? '0'.$hour : $hour;
                    $min = ($min == 0) ? '00' : $min;

                    $options[] = $hour.':'.$min;
                }
            }
        }

        return $options;
    }
}

$hours = range(0, 23, 1);
$mins  = range(0, 45, 15);
$selectBox = new SelectBox();
$selectBox->getTimeOptions($hours, $mins);
Über den Autor

Gjero Krsteski

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen