Wie Services das Dependency Injection Verhalten der Entwickler beeinflusst haben

Spätestens seit der stetig wachsenden Popularität von Unittests, besonders durch PHPUnit, bekam die Auflösung der Abhängigkeiten von Klassen durch Dependency Injection in PHP eine immer größere Rolle im Alltag der Entwickler. Klassen, welche eine oder mehrere Abhängigkeiten zu anderen Klassentypen haben, bekommen diese bei ihrer Erzeugung über den Konstruktor oder zur Laufzeit über Methodenaufrufe übergeben. Dadurch verbessert sich die Wartbarkeit der einzelnen Klassen und Abhängigkeiten lassen sich bei geänderten Anforderungen leichter austauschen. Ebenfalls verbessert sich die Testbarkeit der einzelnen Komponenten, bei der Abhängigkeiten von Klassen durch einfache Test Doubles ersetzt werden können. Ein Nachteil jedoch ist vermehrter Boilerplate Code, wenn an verschiedenen Stellen im Projekt immer die gleichen Objekte erzeugt werden müssen, um die gleichen Abhängigkeiten abzudecken.

Mit den aktuellen PHP-Frameworks wurde der sogenannte Service Locator eingeführt. Die Aufgabe des Service Locator ist die Auflösung und Instantiierung von Abhängigkeiten zu einem Service intern durchzuführen. Dadurch können Objektinstanzen über einen Service erstellt werden, ohne dass dabei der Boilerplate Code zur Auflösung der Abhängigkeiten in der Business Logic hinzugefügt werden muss. Weiterhin sorgt der Service Locator für eine einzige Instanz des aufgerufenen Services innerhalb eines Requests, um unnötige Objekterzeugungen zu vermeiden, ohne dabei die Nachteile eines klassischen Singletons mit sich zu bringen.

Die bequeme Handhabung des Service Locator hat jedoch im Laufe der Zeit die Verwendung von Dependency Injection in Richtungen gelenkt, die zwar technisch schnell umsetzbar sind, aber dessen Sinn nicht ganz folgen. Aus dem Auflösen von Abhängigkeiten wurde ein buntes Zusammenwerfen von Klassen.

weiterlesen »

eval is evil – Stimmt das?

Schon von früh auf wird einem PHP-Programmierer beigebracht, das Sprachkonstrukt eval zu meiden. Dieses führt einen als String übergebenen PHP-Code aus und behandelt diesen wie regulären Code des Projekts. Bereits die PHP-Dokumentation führt aus, dass von der Verwendung dringend abgeraten wird.

Die Gefahr, die in eval steckt, lässt sich sehr einfach darstellen:

< ?php eval($_POST['textarea_value']); 

In diesem Beispiel lässt sich im Formularfeld textarea_value jede versendete Eingabe als PHP-Code ausführen und ermöglicht es einem Angreifer, auf einfache Weise Schaden anzurichten. Natürlich ist die Verwendung und die Gefahr von eval für gewöhnlich nicht so offensichtlich wie in diesem Beispiel, sondern steckt viel mehr in Details, die man als Programmierer übersehen hat. Bevor sich ein Programmierer Gedanken darüber macht, welche Angriffsvektoren in seinem Code durch eval möglich sind und abgefangen werden müssen, lässt er lieber die Finger von dem Sprachkonstrukt. eval is evil.

Aber warum nutzen wir dann Sprachen oder Funktionen, die nicht weniger gefährlich sind? Und wenn eval wirklich so böse ist, wieso wird es in vielen Libraries und Frameworks eingesetzt?

weiterlesen »

Erstellen und Auslesen eigener internationalisierter Ressourcen

Die Internationalisierung von Webprojekten ist ein Thema, dass in der Entwicklung schon sehr früh bedacht werden sollte. Selbst wenn in einem Projekt anfangs noch keine Pläne dafür vorliegen, ist es nicht gesagt, dass dies immer so bleiben wird.

Glücklicherweise bieten PHP-Frameworks inzwischen Werkzeuge dafür an, jedoch hat sich im Verlauf der Wechsel von Major Releases einiges geändert. Informationen zur Internationalisierung und Lokalisierung sind z.T. aus den Frameworks entfallen. Wo Zend Framework 1 noch mit Zend_Locale, seinen Unterklasse und Data XML-Dateien aufwartete, hat der Nachfolger Zend Framework 2 sich ganz von dem Locale Namespace getrennt. Viele der darin enthaltenen Funktionalitäten konnten nun von der Intl PHP-Extension übernommen werden.

Die Intl PHP-Extension bietet mehrere Klassen und Funktionen an, mit der länderspezifische Formatierungen, Sortierungen und Zeitinformationen umgesetzt werden können und ist somit ein Tool, welches schon seit Langem zu jeder guten PHP Installation dazugehören sollte.

Infomationen zur Verwendung der IntlCalendar-Klasse wurden bereits hier erläutert.

Die Unterschiede der verschiedenen Länder sind jedoch so umfangreich, dass früher oder später der Entwickler einen Punkt erreicht, an dem auch die Intl Extension keine passenden Daten bietet. Oder doch?

weiterlesen »

Annotations in PHP

So ziemlich jeder ist schon einmal auf die sogenannten Annotations in PHP-Klassen gestoßen: Metadaten zu Methoden oder Properties, welche zur Laufzeit wie von Zauberhand plötzlich Bestandteil von PHP-Code werden können. Besonders bekannt sind die Annotations von phpDocumentor, welche zu einer kleinen Dokumentation des Codes ausgewertet werden können. Die Annotations zu einer Methode sehen bei phpDocumentor zum Beispiel so aus:

class Foo
{
    /**
     * @param mixed $baz
     * 
     * @return string
     */
    public function bar($baz)
    {
        return (string) $baz;
    }
}

Nicht nur bei einer Dokumentation ist phpDocumentor hilfreich. Viele IDEs nutzen die in den Annotations hinterlegten Werte der Typen auch um bei der Autovervollständigung die richtigen Methoden oder Properties vorzuschlagen.

weiterlesen »

Locale-Falle mit IntlCalendar::fromDateTime()

Mit PHP 5.5 wurde auch die Extension für die Internationalisierung um neue Klassen erweitert. Eine besonders interessante Erweiterung ist die Klasse IntlCalendar, in der verschiedene neue Funktionen bereitgestellt werden um mit Lokalisierungen von Jahren, Wochen oder Tagen umzugehen zu können. Dabei handelt es sich jedoch nicht um Besonderheiten in der Darstellung von Zeit, sondern mehr um deren Betrachtung. In Deutschland sehen wir den Montag als Anfang der Woche an während es in den USA der Sonntag ist. Ebenso wird dank der Lokalisierung bei der Erstellung eines IntlCalendar-Objekts die Auswahl zwischen gregorianischem und julianischem Kalender abgenommen. Das Ganze funktioniert aber auch nur, wenn die Lokalisierung stimmt.

Zur Erstellung eines Calendar-Objekts bietet die Klasse 2 Factory-Methoden:

Während IntlCalendar::createInstance() den aktuellen Zeitpunkt für Berechnungen zur Verfügung stellt, lässt sich mit IntlCalendar::fromDateTime() aus einem PHP DateTime (alternativ auch ein String) ein IntlCalendar-Objekt erstellen.

// createInstance
$calendar = IntlCalendar::createInstance('Europe/Berlin', 'de_DE');

// fromDateTime
$dateTime = new DateTime('25.01.2014', new DateTimeZone('Europe/Berlin'));
$calendar = IntlCalendar::fromDateTime($dateTime);

Da in vielen Projekten DateTime verwendet wird, bietet es sich geradezu an, daraus ein IntlCalendar-Objekt zu erstellen. Wer sich die Factory-Methoden jedoch genau angesehen hat, wird sofort etwas festgestellen: fromDateTime() bietet keine Möglichkeit, eine Locale wie de_DE zu übergeben. Stattdessen wird der Standardwert aus der php.ini verwendet. Sichtbar wird der Fehler dann, wenn zwar die Formatierung über IntlDateFormatter wie die aus dem entsprechenden Land aussieht, jedoch z.B. die Woche mit einem ganz anderen Tag beginnt.

weiterlesen »

Track Memory Usage and Runtime of Symfony Commands

If you write lots of Console Commands in your Symfony application you sure want to know more about their memory and time consumption. To collect the necessary data you can make use of the Stopwatch Component:

use SymfonyComponentStopwatchStopwatch;

$stopwatch = Stopwatch();
$stopwatch->start('my event');
// do something important
$stopwatchEvent = $stopwatch->stop('my event');

echo $stopwatchEvent->getDuration();
echo $stopwatchEvent->getMemory();

First we need to define a service for our Stopwatch in our services.yml to have it available where we want it:

services:
    flagbit_core.stopwatch:
        class: SymfonyComponentStopwatchStopwatch

weiterlesen »

Mime-Type-Problem mit PHP Autoload

Als ich mir heute mit PHP Autoload (phpab) meine Autoload-Datei neu generieren ließ, war ich bass erstaunt. Statt der üblichen 700 Klassen waren plötzlich nur noch 15 Dateien enthalten.

Nach ein bisschen Debuggen kam ich dann recht schnell dahinter, dass die Ursache in der Klasse TheSeerDirectoryScannerPHPFilterIterator liegt:

public function accept() {
    $finfo = new finfo(FILEINFO_MIME);
    return strpos($finfo->file($this->current()->getPathname()), 'text/x-php') === 0;
}

Dort wird nämlich der Mime-Type der Datei überprüft und nur Dateien mit Mime-Type text/x-php werden überhaupt nach Klassen durchsucht. Meine Dateien haben lustigerweise aber zum Großteil text/x-c++ – zumindest wenn ich mir das unter Windows anschaue. In meiner virtuellen Maschine haben die selben Dateien, die dann über vboxsf eingebunden sind, den korrekten Mime-Type.

Klar – ich kann das erstmal umgehen, indem im PHPFilterIterator ein return true einbaue; aber schön ist anders. Hat jemand einen Tipp wie man den Mime-Type einer Datei ändern kann oder noch interessanter: wie das Problem überhaupt entstanden sein könnte? Da es in der Linux-VM korrekt angezeigt wird ist ja vermutlich irgendwas an meinem Windows kaputtkonfiguriert…

Grep für Application-Logs

Bei der Fehlersuche bieten einem die Application-Logs oftmals einen guten Einstiegspunkt. Doch die Suche darin kann zum Teil recht mühsam sein. Vor allem wenn man nicht nach der Fehlermeldung selbst suchen will, sondern zum Beispiel alle Fehler haben will, die einen bestimmten Methodenaufruf im Stacktrace haben. Und dann wollte ich auch nicht nur die Zeile haben, sondern den ganzen Log-Eintrag, inklusive Message und komplettem Stacktrace.

Ich habe mir dafür ein kleines PHP-Skript geschrieben. Vielleicht findet es ja sonst jemand nützlich:

 n";
    exit(1);
}

$filename = 'php://stdin';
if (isset($argv[2])) {
    $filename = $argv[2];
}
$fp = fopen($filename, 'r');

// "2011-11-22T02:16:34+01:00 - "
$startPattern = '#^d{4}(-d{2}){2}Td{2}(:d{2}){2}+d{2}:d{2} - #';
$searchPattern = $argv[1];

$found = false;

while ($line = fgets($fp)) {
    if (preg_match($startPattern, $line)) {
        if (true === $found) {
            foreach ($buffer as $bufferedLine) {
                echo $bufferedLine;
            }
        }

        $buffer = array();
        $found = false;
    }

    if (preg_match($searchPattern, $line)) {
        $found = true;
    }

    $buffer[] = $line;
}

Der Aufruf sieht dann so aus:

$ php loggrep "#Mage_Core_Block_Template#" exception.log

Wichtig ist, dass der Suchbegriff mit PCRE-Syntax (inklusive Delimiter) angegeben wird.

Update 08.11.2011

Jetzt neu: Falls keine Datei angegeben wird, kann das Skript auch von STDIN lesen. Damit kann man auch einfach in gepackten Dateien suchen:

$ zcat exception.log.1.gz | php loggrep "#Mage_Core_Block_Template#"

IPC 2011 – Tag 2

Da wir gestern noch bis spät geschäftliche Besprechungen hatten, haben wir die Keynote heute morgen leider verpasst. Wir sind daher pünktlich für den zweiten Kaffee des Tages vor dem zweiten Slot in der Rheingoldhalle angekommen :)

Den ersten Vortrag des Tages bildete somit „Zend Framework 2: State of the Art“. Enrico Zimuel (Zend) gab einen groben Überblick zu den Veränderungen und Neuerungen in ZF2 und zur aktuellen Zeitplanung: eine erste Beta soll noch im Oktober veröffentlicht werden. Das Autoloading in ZF2 wurde grundlegend erweitert. Zwar unterstützt der Autoloader nach wie vor die alte include-path-basierte Methode, zusätzlich kann man Namespaces mit Verzeichnissen verknüpfen woraufhin der Loader Klassen dieser Namespaces direkt aus dem spezifizierten Verzeichnis lädt. Das bringt laut den Zend-Benchmarks mit Opcode-Cache bis zu 40% Performancegewinn. Bis zu 60% schneller ist der Loader mit einer statischen Classmap. Dabei wird das gleiche Prinzip wie bei Arne Blankerts Autoload verwendet. Dependency Injection wird über Container, Interfaces und Setter ermöglicht, die auch über Annotationen konfigurierbar sind. Beispiele dazu finden sich auf Ralph Schindlers Git-Repository. Ebenfalls neu sein wird der EventManager sowie das eventgetriebene MVC-Framework, dass sich auch modular erweitern lassen soll.

weiterlesen »

IPC 2011 – Tag 1

Juhu, es ist wieder so weit: Konferenz! :) Nach viel zu frühem Aufstehen (7 Uhr) ging es heute morgen auf nach Mainz zur IPC 2011. Dort konnte ich beweisen, dass die Android-Navigation den nächsten McDonalds besser findet als angebissenes Obst. Zur Rheingoldhalle konten beide Navigationssysteme gleich gut navigieren.

Auf der Konferenz angekommen gab Johannes Schlüter (Oracle) zunächst ein Update bezüglich PHP 5.4. Dabei wurde unter anderem auf Traits, die neue Array-Syntax und den internen PHP-Dev-Webserver eingegangen. Verbunden war das Ganze mit der eindringlichen Aufforderung die Nightly-Builds zu testen um solche Bugs wie in PHP 5.3.7 und andere zu vermeiden. PHP würde zwar von einer Test-Suite getestet, doch „unbeabsichtigte“ (sprich: nicht im Sinne der PHP-Entwickler) Verwendungen von Funktionen würden von dieser Test-Suite eben nicht erfasst, was auch zum aktuellen Problem mit der is_a()-Funktion führe.

weiterlesen »

« Vorherige Einträge