Archiv der Kategorie: PHP

Rezension: Softwarequalität in PHP-Projekten von Sebastian Bergmann und Stefan Priebsch, 2. Auflage

Man kann sich viele Bücher zum Thema Qualitätsverbesserung in IT-Projekten zulegen, manchmal kann man während der Lektüre sogar was lernen, in den wenigsten Fällen hat man es dabei mit konkreten Programmiersprachen zu tun und noch viel weniger sind in Deutsch.
Da scheint es ein wahrer Lichtblick zu sein, dass zwei der bekanntesten PHP-Experten das Standardwerk zur Qualitätsverbesserung und -sicherung noch einmal überarbeitet haben, teilweise sogar neu geschrieben haben. Herausgekommen ist ein absolutes „must-have“.

Sebastian Bergmann und Stefan Priebsch beschreiben auf circa 460 Seiten, worauf der Qualitätsbewusste PHP-Entwickler achten muss und soll. Angefangen vom „Was ist denn eigentlich Qualität und wie kann man diese Messen?“ über „und warum ist das wichtig?“ bis hin zum „Wie sag ich’s meinem Kunden“ schreiben beide in einem lockeren Stil über eines der komplexesten Themen innerhalb des Programmieralltags.

„Softwarequalität in PHP-Projekten“ ist sicherlich kein Buch zum einfachen „runter lesen“, sondern man ertappt sich öfters dabei, eine Seite nun das x-te mal gelesen und dann doch noch das Gefühl zu haben, etwas nicht richtig verstanden zu haben. Kleiner Tip: Hier hilft es sehr, die Beispiele wirklich abzutippen und das Thema mal auszuprobieren. Frei nach dem Motto „Probieren geht über Studieren“ lösen sich dann die Fragen meist in Erkenntnis auf.

Schön zu lesen sind auch die Fallbeispiele von Typo3, Zend Framework und allen weiteren. Auch die „großen“ machen Fehler und manche lassen sich hier nachlesen. Das schöne Gefühl von „die konnten es auch nicht sofort“ stellt sich ein und lässt einen etwas beruhigter zurück.

Meine Favoriten waren die Kapitel über „Legacy Code“, „Kontinuierliche Integration“ und „Bad Practices“. Ich persönlich fand ich den präsentierten Legacy Code zwar nicht legacy genug, aber das liegt sicherlich auch an mir und meinem Background. Übertragbar sind trotzdem viele der Wege und Tips auf (noch viel) älteren Code – alles schon ausprobiert 😀

Will man nun was negatives finden, man könnte anbringen, dass die Beispiele in sich manchmal nicht konsistent sind oder der eigentlich Kern, was Bergmann und Priebsch sagen wollen, nicht immer anhand der Beispiele ersichtlich wird. Hier und da hätten die Beispiele kürzer, dafür mehr auf den Kern reduziert sein können, es hätte zu etwas schnelleren „Aha!“-Momenten geführt. Aber das wäre jammern auf einem sehr hohen Niveau. Dieses Buch richtet sich definitiv nicht an Einsteiger, die sich an solchen Dingen stören würden; es richtet sich vor allem an Profis oder interessierte Fortgeschrittene, die sich noch weiter verbessern wollen, noch näher an den „perfekten Code“ kommen wollen. Und dieses Wissen zu vermitteln schafft dieses Buch locker.

Mein Tip: Kaufen, Lesen, Verstehen (nicht auswendig lernen). Ich habe selten so ein gutes (Fach-)Buch gelesen! Wenn ihr nur wenig Budget zur Verfügung habt, euch aber die Qualität eures Codes (und eures Handwerks) nicht egal ist, dann kauft dieses Buch. Ihr werdet sehr lange Lesefreude daran haben und euer Code wird es euch danken.

tl;dr: Unbedingt kaufen und verinnerlichen

XDebug Logo

XDebug und Zend Server CE für Unit Tests und Code Coverage Reports

Wer Unit Testing betreibt, der will auch Code Coverage, ganz klare Sache. Für Code Coverage benötigt man in Verbindung mit phpUnit XDebug. In der Regel kein Problem.

Wer allerdings den ZendServer benutzt der war bisher angeschmiert, den XDebug im ZendServer zu konfigurieren kann nervig sein und eine falsch eingetragene Zeile kann den Betrieb des ZendServers sogar komplett lahmlegen.

Aber natürlich gibt es einen Weg, XDebug, ZendServer inkl. ZendDebugger laufen zu lassen, du bekommst also den ZendDebugger zum debuggen und XDebug zum Unit Testen deiner Anwendung, das beste aus beiden Welten – unter Windows 😉

Bereit? Los geht’s:

  1. ZendServer stoppen, entweder per Dienstkonsole oder mit „Apache Service Monitor“
  2. Lade dir die fehlende XDebug dll bei XDebug.org runter.
    Welche ist die passende?
    Zunächst erstmal die PHP Version deines ZendServers, dann den Link OHNE „TS“ und den mit 32-Bit, der sollte passen – war bisher bei allen meinen ZendServer-Installationen so.
    Beispiel mit PHP 5.4: „PHP 5.4 VC9 (32 bit)“
  3. Die .dll legst du nun im Verzeichnis
    /ZendServer/lib/phpext

    deines ZendServers ab.

  4. Nun ab in die php.ini
    Dort trägst du ziemlich weit unten aber ÜBER diesem Eintrag:

    zend_extension="C:\zend\ZendServer\lib\ZendExtensionManager.dll"

    (Pfad ist bei dir zumindest ähnlich)
    das hier ein:

    zend_extension="C:\zend\ZendServer\lib\phpext\php_xdebug-2.2.2-5.4-vc9-nts.dll"

    Natürlich ersetzt du den konkreten Namen durch deinen, bei mir ist das der ZendServer mit PHP 5.4 in der zum Veröffentlichungszeitpunkt aktuellsten Version von XDebug.

  5. Spaß mit Code Coverage!
    Ja, genau, schon fertig.

Ab nun kannst du Code Coverage Reports bekommen.

Was nicht geht: Du kannst mit XDebug (höchstwahrscheinlich) nicht wirklich debuggen – aber du hast ja den Zend Debugger, der zumindest mit dem Zend Studio wesentlich besser funktioniert.

Ich selbst habe bisher keine verlässlich funktionierende Konfiguration gefunden, mit dem ich via XDebug im Zend Server debuggen und profilieren konnte; mir reicht XDebug zum erzeugen der Code Coverages.

Vielen Dank geht an „Limespacer“ für diesen Beitrag, der mir dabei sehr geholfen hat:
http://www.limespace.de/2009/07/15/zend-server-ce-mit-xdebug/

P.S. Bei mir geht es auch mit aktiviertem Zend Debugger, falls das bei dir nicht der Fall sein sollte, dann schalte diesen wie im verlinkten Beitrag gezeigt einfach ab.

Welche Dateien werden grade benutzt?

Besonders bei Legacy-Anwendungen stößt du häufig an den Punkt, dass eine bestimmte Funktion mehrfach deklariert wurde. In meinem extremsten Falle war das sogar in bis zu 12 Dateien – die gleiche Funktion, in 12 Dateien, zwölf!

Na gut, das ist echt die Ausnahme, Legacy Anwendungen tendieren zu einem Durchschnitt von 2-3 redundaten Funktionsdeklarationen, aber selbst das ist zuviel.

Nun möchtest du natürlich wissen, welche Funktion in deinem Fall nun konkret aufgerufen wird, damit du dem Kunden schnell und verlässlich die lang erwartete neue Funktion einbauen und vorführen kannst. Mit einer IDE geht es recht schnell, STRG+Linksklick beherrschen seit dem Visual Studio so gut wie alle IDEs – wobei es auch hier schon oft vorgekommen ist, dass selbst die IDE es nicht wusste und alle 3 vorkommen vorschlug. Ja Herrschaftzeiten, woher soll ICH denn bitteschön wissen, welche der drei Dateien denn nun aufgerufen wird?

Ganz einfach, mit get_included_files() bekommst du es heraus.

$included_files = get_included_files();
var_dump($included_files);

Und nun dürfte es etwas leichter fallen, die Wunschfunktion des Kunden einzubauen. Aber nur etwas 😉

Zend Certified Engineer (ZCE)

Geschafft! Seit Mittwoch gehöre ich zum Kreise der „Zend Certificated Engineer PHP 5.3“ kurz ZCE. Den Beweis dazu trete ich auch leicht an, hier mein Eintrag in den Zend Yellow Pages zu meinem Profil. Ich bin sehr stolz, dass ich dies geschafft habe.

Vorbereitet habe Ich mich sehr lange und intensiv auf die Prüfung und war nachher eigentlich überrascht, dass ich so schnell fertig war (ich hatte noch 40 Minuten von meinen 90 übrig). Ein großes „Danke“ geht auch an meinen Arbeitgeber, der mir das Zertifikat gesponsert hat.

Ausruhen möchte ich mich jedoch auf diesem Erfolg nicht, das nächste Zertifikat wäre in meinen Augen das des „Oracle Certified Professional, MySQL 5 Developer“ oder gibt es in euren Augen noch „sinnvollere“ Zertifikate, die man als PHP-Entwickler anstreben sollte?

header-Umleitung funktioniert nicht? Ursache finden …

Wenn’s mit dem

header('Location: http://www.example.com');

mal nicht funktioniert, liegt es daran, dass schon eine Ausgabe vorher stattgefunden hat.

Manchmal kann es aber durchaus kompliziert sein, diese Ausgabe zu finden, teilweise meldet auch das error.log nichts, dann hilft dir eine freundliche PHP-Funktion weiter, die du zu Testzwecken direkt vor das header-Kommando stellst:

$file = ''; 
$line = ''; 
headers_sent($file, $line); 
print_r($file, $line);

headers_sent zeigt dir nun die Stellen , die vorher bereits eine Ausgabe durchgeführt haben.

Automatische Validierung mit dem W3C-Validator

Das W3C stellt eine sehr elegante API bereit, mit deren Hilfe man recht einfach Seiten automatisiert überprüfen kann, ob die Seiten Fehler hat und wenn ja, welche das sind.

Ich stelle das mal mit Hilfe des Zend Frameworks vor, da es damit wirklich sehr trivial ist.

<?php
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();

$client = new Zend_Http_Client();
$result = $client->setMethod(Zend_Http_Client::POST)
->setUri('http://validator.w3.org/check')
->setParameterPost('uri', 'https://www.codemercenary.de')
->request();

Zend_Debug::dump($result->getHeaders());
file_put_contents('w3cresult.html', $result->getBody());

Als Ausgabe erhält nun die Header

array(12) {
'Date' =>
string(29) "Thu, 11 Oct 2012 12:03:20 GMT"
'Server' =>
string(22) "Apache/2.2.16 (Debian)"
'Content-language' =>
string(2) "en"
'X-w3c-validator-recursion' =>
string(1) "1"
'X-w3c-validator-status' =>
string(7) "Invalid"
'X-w3c-validator-errors' =>
string(2) "48"
'X-w3c-validator-warnings' =>
string(1) "3"
'Vary' =>
string(15) "Accept-Encoding"
'Content-encoding' =>
string(4) "gzip"
'Content-length' =>
string(4) "7228"
'Content-type' =>
string(24) "text/html; charset=UTF-8"
'Connection' =>
string(5) "close"
}

Die Header kann nun recht einfach vergleichen, bei „X-w3c-validator-status“ kann man mittels test auf „Invalid“ schnell feststellen, dass was nicht funktioniert hat. Eine kurze Übersicht über die Anzahl der Fehler und Warnungen ist auch mittels Headeranalyse möglich.

Weitere Details stehen dann im Body, den ich im Beispiel in der letzten Zeile mal eben schnell auf die lokale Festplatte downloade.

So, das war der Crashkurs zum Thema „W3C-Validierung-Prüfung mit PHP“, weitere Infos findet ihr beim W3C in der API Doku: http://validator.w3.org/docs/api.html

php Codesniffer und CI , Zeilenlänge und Windows Zeilenumbruch setzen

Windows, Continous Integration, 16:10 Bildschirme und phpcs.

Dies alles passt im Standard nicht zusammen, zumindest nicht mit unseren internen Regeln, daher hier die notwendigen Anpassungen, um zumindest die Zeilenlänge auf ein erträgliches Maß von 120 zu 160 zu bekommen (nicht mit dem Blutdruck verwechseln) und den Codesniffer an Windows-like Zeilenumbrüche von \r\n zu gewöhnen.

Meine phpcs.xml sieht dann in etwa so aus:

<?xml version="1.0"?>
<ruleset name="PHPCS Rules">
 <description>Using Zend Rules</description>
 <rule ref="Zend">
  <exclude name="Generic.WhiteSpace.DisallowTabIndent" />
  <exclude name="Generic.Functions.OpeningFunctionBraceBsdAllman" />
  <exclude name="Generic.PHP.DisallowShortOpenTag" />
  <exclude name="Generic.Files.LineEndings" />
 </rule>
 <rule ref="Generic.Functions.OpeningFunctionBraceKernighanRitchie" />
 <rule ref="Generic.Files.LineLength">
  <properties>
   <property name="lineLimit" value="120"/>
   <property name="absoluteLineLimit" value="160"/>
  </properties>
 </rule>
</ruleset>

PHP XML Daten in einer Session speichern

Beim Versuch, SimpleXML Objekte in eine Session zu speichern solltet ihr folgendes Wissen.

Ein trivialer Ansatz wie

if (!isset($_SESSION['xml'])) {
  $xml = simplexml_load_string($myxmlstring);
  $_SESSION['xml'] = $xml->someNode;
}
var_dump($_SESSION['xml']);

wird fehlschlagen. Im ersten Moment sind die Daten in der Session offenbar gespeichert, beim nächsten Aufruf der Seite werden allerdings alle values verschwunden sein, d.h. der xml-Key der $_SESSION ist zwar vorhanden (weshalb auch das Neuladen übersprungen wird), aber $_SESSION[‚xml‘] = null.

Ihr umgeht das Problem, in dem ihr jeden Wert, den ihr speichern wollt, vorher explizit Typkastet und dann erst in die Session einbringt:

if (!isset($_SESSION['xml'])) {
  $xml = simplexml_load_string($myxmlstring);
  $_SESSION['xml'] = array(
    'someNode' => (int)$xml->someNode,
    'otherNode' => (string)$xml->other->node[0]->attribName,
}
var_dump($_SESSION['xml']);

Nun erhaltet ihr die Werte bei jedem Aufruf und könnt die eingelesenen Werte in der Session transportieren.

Vorsicht bei mysql_connect und Vielfachverbindungen

Eine der automatischen „Goodies“ bei mysql_connect (wen man es denn schon nutzen muss, warum auch immer), ist, dass, wenn man mysql_connect mit den gleichen Informationen bestückt, diese Funktion die gleiche Verbindungsid zurückgibt wie beim ersten mal … es wird also keine zweite Verbindung aufgebaut.

Das Problem ist nun leider, dass der, der die zweite Verbindung öffnen möchte, diese Informationen _ganz genau_ braucht, denn sonst erhält man unter Umständen trotzdem eine zweite Verbindung, obwohl man die vermeindlich gleichen, aber nicht selben Parameter benutzt.

Beispielcode:

$dbserver1 = '127.0.0.1';
$dbserver2 = 'localhost';

$dbuser1 = 'root';
$dbuser2 = 'Root';
$dbpass = '';

$db1 = mysql_connect($dbserver1, $dbuser1, $dbpass);
$db2 = mysql_connect($dbserver2, $dbuser2, $dbpass);
$db3 = mysql_connect($dbserver1, $dbuser2, $dbpass);
$db4 = mysql_connect($dbserver2, $dbuser1, $dbpass);
$db5 = mysql_connect($dbserver1, $dbuser1, $dbpass);

var_dump($db1, $db2, $db3, $db4, $db5);

Ausgabe:

resource(7) of type (mysql link)
resource(9) of type (mysql link)
resource(11) of type (mysql link)
resource(13) of type (mysql link)
resource(7) of type (mysql link)

Hier zeigt sich, dass insg. 4 verschiedene Connection-Ids zurück gegeben wurden, $db5 ist zur Kontrolle und zeigt, dass nur die exakt selben Parameter zum gewünschten Ergebnis kommen, nämlich die selbe ID zu benutzen, die schon bei $db1 erzeugt wurde.
Im Realfall würde dies nun 4 Prozesse bedeuten, von denen 3 überflüssig sind und nur den Server belasten … pro Aufruf im schlimmsten Fall.