Seit dem FLOW3 Release 1.0 haben wir viele Anfragen für interessante Projekte rund um das neue PHP-Framework bekommen. Auch unser erstes größeres FLOW3-Projekt ist seit dem Release-Datum live und läuft zuverlässig. So ein Launch zieht natürlich etwas Arbeit nach sich, so dass von uns über dieses fast historische Ereignis aus Zeitgründen noch kein Blogeintrag verfasst wurde.

Deswegen schauen wir jetzt mal ein bisschen nach vorne:

Was wird das nächste Release bringen?

Ein wirklich wichtiges Feature, welches in 1.0 zwar vorhanden, jedoch noch nicht nutzbar war, ist das Thema Lokalisierung und Internationalisierung (oder abgekürzt I18n).

Zur Ausgabe von lokalisierten Texten (zum Beispiel Meldungen bei der Validierung oder Labels in Formularen) ist es unumgänglich einen Mechanismus zur Übersetzung anzubieten. Auch die Ausgabe von Datum und Uhrzeit, Zahlen oder Währungen müssen an landesspezifische Eigenheiten angepasst werden. Eine Möglichkeit zur Definition der Sprachdateien bietet dabei der XLIFF-Standard, der mit TYPO3 4.6 auch Einzug in die bestehende Version des CMS gehalten hat. Ein TranslationProviderInterface bietet dabei Flexibilität für andere Implementierungen. Als Entwickler wird man dabei hauptsächlich mit der Klasse Translator oder dem <f:translate> View-Helper in Berührung kommen. Neben der Adressierung von Labels über einen Key (bekannt aus TYPO3) ist es nun auch möglich anhand des Originaltexts zu übersetzen.

Translations im PHP-Code:

// Get label by id
$label = $this->translator->translateById('update');
// Get label by original label
$label = $this->translator->translateByOriginalLabel('Authentication required');

Translations im Fluid-Template:

<!-- Translate by id with default text for missing translation -->
<f:translate key="user.unregistered">Unregistered User</f:translate>
<!-- Translate by text -->
<f:translate>Unregistered User</f:translate>

Der sogenannte FormatResolver bringt dabei flexible Argumente mit Umwandlung von lokalisierten Formaten ins Spiel. So können Zahlen und Datumsangaben oder auch eigene Werte flexibel in Übersetzungen umgewandelt werden:

// Translate by original label with formatted argument
$label = $this->translator->translateByOriginalLabel('Record {0,number} saved', NULL, array(42));
// $label => "Record 42 saved"

Performance, Performance, Performance

Neben allgemeinem Feintuning und dem Feedback der ersten Anwender gibt es jedoch einen besonderen Schwerpunkt für das Release 1.1: die Performance (besonders im Production Context) und der Ressourcenverbrauch. Natürlich ist ein umfangreiches Framework wie FLOW3 immer etwas langsamer als ein genau auf einen Zweck geschriebenes und optimiertes Script, jedoch sollten dabei immer die Kosten eines Projekts gegenübergestellt werden. Spart ein Entwickler Zeit und wird die Wartung in Zukunft vereinfacht sind zusätzliche Kosten für mehr Hardware schnell eingespart. Jedoch zeigte sich in einigen Teilen des Frameworks wie z.B. dem ReflectionService erhebliches Optimierungspotenzial. Auch der Bootstrap, also die Initialisierung von FLOW3 ist mit 1.1 für Performance Optimierungen und Feintuning wesentlich flexibler geworden. Als positiver Nebeneffekt können Pakete nun über RequestHandler flexibel in den Bootstrap eingreifen und eine eigene Initialisierung vorgeben. So können nur die Teile des Frameworks geladen werden, welche für einen Request benötigt werden. Gerade für service-orientierte Applikationen bringt dies einen Vorteil.

Im Beispiel des TYPO3.Soap Package kann so z.B. ein optimierter RequestHandler benutzt werden:

class Package extends BasePackage {
	public function boot(\TYPO3\FLOW3\Core\Bootstrap $bootstrap) {
		$bootstrap->registerRequestHandler(new RequestHandler($bootstrap));
	}
}
 
class RequestHandler implements RequestHandlerInterface {
	public function handleRequest() {
		$sequence = $this->buildRuntimeSequence();
		$sequence->invoke($this->bootstrap);
		...
	}
	public function buildRuntimeSequence() {
		$sequence = $this->bootstrap->buildEssentialsSequence();
		// Declare new step typo3.flow3:objectmanagement:proxyclasses to run after typo3.flow3:systemlogger
		$sequence->addStep(new Step('typo3.flow3:objectmanagement:proxyclasses', array('TYPO3\FLOW3\Core\Booting\Scripts', 'initializeProxyClasses')), 'typo3.flow3:systemlogger');
		...
	}
}

Wie man sieht kann ein Step in einer Bootstrap Sequence dynamisch Abhängigkeiten auflösen und eine individuelle Initialisierung implementieren.

Weitere Optimierungen:

  • FreezableBackendInterface für Caches, die ein “einfrieren” des Zustands für einen rein lesenden Zugriff unterstützen. Ermöglicht ein optimiertes Laden von Proxyklassen, denn im Production Context muss jetzt nicht mehr geprüft werden, ob ein Cache-Eintrag abgelaufen ist.
  • Optimierter ClassLoader mit einem neuen symbolischen Link Packages/.Shortcuts, welcher einen direkten Zugriff auf Packages liefert, unabhängig von Unterordnern in Packages.
  • Optimierte Initialisierung des PackageManager, die einen kompletten Scan der Paketverzeichnisse nur noch im Development Context oder beim initialen Aufruf erfordert.

Insgesamt konnte durch die vielen kleinen und einigen größeren Änderungen im Kern des Frameworks ein deutlicher Geschwindigkeitszuwachs mit reduziertem Speicherverbrauch erreicht werden. Wer also bisher an der Performance von FLOW3 zweifelte, sollte das Framework noch einmal ausgiebig testen.

Genau das hat das Core-Team nämlich auch gemacht. Mit einem neuen Paket für das Profiling können Speicherverbrauch und aufgewendete Zeit in verschiedenen Teilen des Frameworks auch durch Anwender einfach ausgewertet werden. Bisher musste dafür ein komplettes Profiling mit xhprof oder xdebug durchgeführt und vor allem ausgewertet werden. In umfangreichen Loadtests in einem realistischen Szenario hat sich der Durchsatz für eine unserer Applikation um den Faktor 2 verbessert. Durch den geringeren Ressourcenverbrauch blieb dabei die Latenz wesentlich konstanter als vor den Optimierungen.

Mehr Sicherheit

Schon mit Release 1.0 war mit PBKDF2 ein starkes Hashing von Passwörtern im Security-Framework implementiert. Jedoch hat die Implementierung in PHP einen Nachteil in der Anzahl der möglichen Hashing-Iteration. Mit einer neuen BCryptHashingStrategy (ab 1.1 der Standard) und der Unterstützung für mehrere Hashing-Strategien können in einem System unterschiedliche Hashing-Mechanismen benutzt werden. Auch zukünftige Migrationen sind so möglich.

Ausblick

Natürlich wurden noch viele andere Änderungen durchgeführt, die sicherlich im endgültigen Changelog Beachtung finden werden. Release 1.1 wird FLOW3 in Sachen Stabilität und Geschwindigkeit auf eine neue Stufe bringen und ermöglicht durch die renovierte Initialisierung mehr Flexibilität. Lokalisierung und Internationalisierung werden mit dem I18n-Framework vervollständigt, was eine der letzten Lücken im Funktionsumfang von FLOW3 schließt.