PHP-Entwicklung: Full-blown IDE vs. Text-Editor

Das Entwickeln von PHP-Applikationen ist die Tätigkeit, mit welcher ich die meiste Zeit des Tages beschäftigt bin. Das ist Grund genug, ständig nach Dingen zu suchen, die mir diese Arbeit erleichtern.

Das zentrale Tool für die Entwicklung ist dabei das Programm, in welchem ich Code eingebe, ändere, suche, ersetze, verwalte und vieles mehr. Gerade hier ist über die Jahre eine Menge passiert, vieles aber doch gleich geblieben. Anfangs – noch als Windows-Nutzer – habe ich Editoren wie z. B. SciTe, Notepad++, UltraEdit o. Ä. zum Coden benutzt. Da er bei der Arbeit auf Servern zu den wichtigsten Tools gehörte und allgegenwärtig war, lernte ich später auch Vim und nutzte ihn dann in der grafischen Version GVim als meinen primären PHP-Editor.

Mit dem Umstieg auf OS X rutschte Vim als Alltagseditor etwas aus dem Fokus, was auch daran lag, dass es damals noch keine anständige Umsetzung für den Mac gab (diese wurde dann in Form von MacVim um 2007 oder 2008 veröffentlicht). Zwischenzeitlich wechselte ich – wie vermutlich fast jeder zu dieser Zeit – auf TextMate, welcher mit seinen Plugins (im TextMate-Sprech Bundles genannt) unfassbar leistungsfähig war.

Hin und wieder wagte ich den Blick über den Tellerrand und schaute mir integrierte Entwicklungsumgebungen mit PHP-Support an. Es gab zwar durchaus einige (mir fallen spontan NetBeans, Komodo, Eclipse PDT und Zend Studio ein) aber nichts konnte mich überzeugen. Ich ließ mir aber ein fertig konfiguriertes NetBeans liegen, welches ich zum Step-by-Step Debuggen nutzte – das war das einzige wichtige Feature, das mir TextMate nicht bieten konnte.

Die IDE-Welt wurde dann mit dem Erscheinen von JetBrains PhpStorm hart durchgerüttelt. PhpStorm wuchs gerade in den letzten beiden Jahren zum defacto-Standard der PHP-IDEs heran. Nach und nach verlagerte ich meine PHP-Entwicklung auch komplett nach PhpStorm. JetBrains legt in einer unglaublichen Geschwindigkeit neue Features nach, auch die Unterstützung neuer PHP-Versionen und Tools wie Composer ließen nie lange auf sich warten.

Auch ein Grund, mit dem mich JetBrains überzeugen konnte, jedes Jahr etwas Geld auszugeben um die Lizenz zu verlängern, war der Umstand, dass PhpStorm für eine riesige Java-Desktop-Applikation ausreichend schnell war.

Leider hat sich das zuletzt geändert. Auch auf neuen Rechnern fühlt sich PhpStorm nicht mehr flüssig an, es ruckelt mittlerweile an allen Ecken und Enden. Dieser Umstand führte in letzter Zeit dazu, dass ich wieder öfter zum Text-Editor greife, statt PhpStorm zu booten.

Zum Glück ist der Markt der Text-Editoren lebendig wie nie zuvor. TextMate kommt seit einiger Zeit in Version 2 (Beta) daher und ist immer noch wunderbar zum Entwickeln von PHP-Applikationen mit allem was dazu gehört geeignet. Github hat mit Atom einen nagelneuen Editor entwickelt, auch wenn dieser konstruktionsbedingt (basiert auf dem Chromium-Browser) ein paar Nachteile hat. Seit einigen Jahren ist allerdings Sublime Text der Platzhirsch der Code-Editoren. Sublime Text bietet wie auch TextMate Unterstützung für Plugins und kann so auf den eigenen Bedarf angepasst werden und ist auch bei großen Projekten unfassbar schnell. Grund genug, dass ich seit einiger Zeit vermehrt Sublime Text als Editor statt PhpStorm zum Entwickeln nutze.

Gerade zuletzt musste ich sehr viele kleinere Änderungen in vielen Projekten in kurzer Zeit durchführen – die Geschwindigkeit von Sublime Text (in allen Belangen: Projekte öffnen, suchen über das gesamte Projekt, ersetzen usw.) hat das alles überhaupt erst erträglich gemacht.

Alles in allem ist es interessant zu sehen, wie sich der Kreis schließt und schlussendlich doch wieder der einfache Text-Editor das Tool meiner Wahl wird wenn es ums Coden geht.

PHP: foreach vs. array_reduce

Ich habe letztens meine PHP-Library phpgeo mit Scrutinizer CI auf Code-Qualität untersuchen lassen. Es wurde an zwei Stellen Code-Duplication angemahnt, die ich dann auch gleich entfernt habe.

Dabei stieß ich auf eine foreach-Schleife, welche für die Berechnung der Länge einer Polyline (GPS-Track) zuständig ist.

Das Ergebnis der Schleife lässt sich auch wunderbar mit PHPs Funktion array_reduce berechnen. Die Frage war jetzt, ob ich es so lasse wie gehabt oder tatsächlich auf array_reduce umstelle.

Die betreffende Methode:

public function getLength(DistanceInterface $calculator)
{
    $distance = 0.0;

    if (count($this->points) <= 1) {
        return $distance;
    }

    foreach ($this->getSegments() as $segment) {
        $distance += $segment->getLength($calculator);
    }

    return $distance;
}

lässt sich auch so schreiben:

public function getLength(DistanceInterface $calculator)
{
    $distance = 0.0;

    if (count($this->points) <= 1) {
        return $distance;
    }

    return array_reduce(
        $this->getSegments(),
        function($carry, $item) use ($calculator) {
            return $carry + $item->getLength($calculator);
        }
    );
}

array_reduce müsste schon mindestens einen relevanten Vorteil gegenüber foreach bieten und außer der Geschwindigkeit und vielleicht ein bisschen mehr Eleganz fiel mir keiner ein. Die Geschwindigkeit lässt sich zum Glück schnell testen und ein kurzes Skript für diesen Zweck war schnell geschrieben:

<?php
/**
 * we need something to call
 */
function calculate_something($value) {
    return $value / ($value + 1);
}

$cycles = 100000;

// create some random data
$array = [];
for ($i = 0; $i < $cycles; $i ++) {
    $array[$i] = mt_rand(0, 0x7fffffff);
}

$timer['start'] = microtime(true);

$sumForeach = 0;
foreach ($array as $value) {
    $sumForeach += calculate_something($value);
}

$timer['foreach'] = microtime(true);

$sumArrayReduce = array_reduce($array, function($carry, $item) {
    return $carry + calculate_something($item);
});

$timer['array_reduce'] = microtime(true);

echo $sumForeach . " == " . $sumArrayReduce . PHP_EOL;
echo "foreach     : " . ($timer['foreach'] - $timer['start']) . PHP_EOL;
echo "array_reduce: " . ($timer['array_reduce'] - $timer['foreach']) . PHP_EOL;

Es zeigte sich, dass foreach deutlich schneller ist als array_reduce:

[mj@neptune:~/tmp]
% php test.php
99999.999335167 == 99999.999335167
foreach     : 0.068737030029297
array_reduce: 0.2411630153656

Wenn man darüber nachdenkt ist auch schnell klar warum das so sein muss: Für jeden Wert des Arrays wird in array_reduce ein – in PHP relativ teurer – Funktionsaufruf fällig (nämlich die Callback-Closure), was in foreach nicht notwendig ist.

Ende der Geschichte: Die Längenberechnung in phpgeo geschieht weiterhin in einer foreach-Schleife.

Es ist allerdings leicht vorstellbar, dass der Overhead eines Funktionsaufrufes bei anderen Anwendungen weniger ins Gewicht fällt und dort array_reduce die elegantere Alternative darstellen kann.