Mittwoch, 30. Juni 2010

funktionen vs konstanten ; echo vs printf

Gleich zwei Sachen in einem. Ich muss oft an alten Code. Mal muss ich dort eine neue Funktion implementieren, mal ein Bugfix durchführen, usw. usw. Kennen viele von euch. Derzeit muss ich an alten Code, um ein altes Projekt mit vielen neuen Features auszustatten.

"Dabei könnte ich doch gleich mal an der Performace-Schraube drehen..."

...denke ich mir so und nachdem ich viele offensichtliche Bremsen entfernt habe wende ich mich dem Profiling-Report aus dem Zend Studio zu. Nach einiger Zeit kommt in mir eine interessante Frage auf. Da im Code an vielen Stellen solche Konstrukte verwendet werden:

Datei1.php

function getDBName() { return 'meinDBName'; }

Datei2.php

$dbName = getDBName();

Ich denke mir intuitiv: Konstanten wären schneller, aber solch eine Vermutung ist schnell geäußert - Beweise müssen her. Und da ich schon dabei bin und das Projekt noch eins von den echo-HTML Projekten ist (habe ich erwähnt, dass es schon älter ist?), kommt gleich die nächste Frage: echo oder printf?

Meine Vermutung: Aufrufe von Konstanten und die Verwendung von printf ist die schnellste Variante!

Hier also mein Test-Code:

$rounds=999;
function getStringOne() { return 'Hallo'; }
function getStringTwo() { return 'Welt'; }
define("StringONE", 'Hallo');
define("StringTWO", 'Welt');

$start=microtime(1);
for ($i=0;$i<$rounds;$i++)
 echo getStringOne() . ' ' . getStringTwo() . " - ";
$endFunction1=microtime(1);

for ($i=0;$i<$rounds;$i++)
 printf('%s %s - ',getStringOne(),getStringTwo());
$endFunction2=microtime(1);

for ($i=0;$i<$rounds;$i++)
 echo StringONE . ' ' . StringTWO . " - ";
$endConstant1=microtime(1);

for ($i=0;$i<$rounds;$i++)
 printf('%s %s - ',StringONE,StringTWO);
$endConstant2=microtime(1);

printf("Rounds: %u\n",$rounds);
printf("Funktion echo: %f\n",($endFunction1-$start));
printf("Funktion printf: %f\n",($endFunction2-$endFunction1));
printf("Konstanten echo: %f\n",($endConstant1-$endFunction2));
printf("Konstanten printf: %f\n",($endConstant2-$endConstant1));
exit;

Und das Ergebnis:

Funktion echo: 0.025293
Funktion printf: 0.024530
Konstanten echo: 0.017224
Konstanten printf: 0.017751

Meine erste Vermutung - Konstanten sind schneller als Funktionen - hat sich bewahrheitet; meine zweite Vermutung - printf ist schneller als echo - nur zum Teil. Ich bekomme da zum Teil Ergebnisse nach dem Motto "e;Mal so, mal so"e; und kann das nun an diesem Code nicht eindeutig beantworten. In einer Variante habe ich die Rundenzahl auf 99.999 erhöht und in diesem Test waren alle Aufrufe mit printf langsamer als die echo-Varianten, allerdings nicht wirklich signifikant.

Die Frage echo oder printf ist wohl eher eine Geschmacksfrage; für mich im aktuellen Projekt heißt das: Die echo's können bleiben, es bringt mehr, meine Zeit auf die "Entfunktionalisierung" zu verwenden.

Montag, 28. Juni 2010

Telefonnummer nicht als Skype-Link anzeigen

Kennen sicherlich ein paar Leute, man platziert auf einer Seite eine Telefonummer und wundert sich dann über komische Bug-Reports, bei denen es um Layout-Probleme geht.
Irdendwann findet Mensch dann raus: Beim Reporter des Problems werden die Telefonnummern in Skype-Links umgewandelt und die zerschießen dann das Layout.

skypelinks1

In manchen Foren findet Mensch dann den Hinweis, doch bitte eine Meta-Tag einzubauen, allerdings funktioniert dieses nicht immer (in meinem Test machte es überhaupt keinen Unterschied, ob das Tag da war oder nicht, die Nummer wurde immer als Skype-Link dargestellt.
Der Vollständigkeit halber: Hier ist es, evtl. funktioniert es ja beim ein oder anderen:

<meta name="skype_toolbar" content="skype_toolbar_parser_compatible" />

Allerdings: Dank dieses Blogbeitrags von Michael funktioniert nun die Blockade des Umwandelns sehr gut und zuverlässig. Er bedient sich dazu eines kleinen Tricks.


Skype wandelt nur Nummer um, die es erkennen kann. In HTML gibt es ein nettes Tag, SHY. Es sorgt bei Zeilenumbrüchen dafür, dass an definierten Stellen (dort wo &shy; platziert ist) eine Zeilenumbruchsanzeige (ein -) erstellt wird, so dass man bei komplizierten Wörtern einen Grammatikalisch richtigen Zeilenumbruch im Wort platieren kann. Der Browser wird - so denn der Text umgebrochen werden muss - an der Stelle des &shy; den Umbruch anzeigen. Und nun: Muss der Text nicht umgebrochen werden, wird auch nichts angezeigt!


skypelinks2


Ich füge das &shy; nun ganz weit vorn ein, Skype kann nun mit diesem Link nichts mehr anfangen und wir können endlich unsere Nummer so anzeigen, wie es sein sollte.

Freitag, 25. Juni 2010

Füllen von array-Werten in Reihenfolge: for vs range

Will man ein Array mit Werten füllen, die in einer Reihenfolge stehen (a-x, 1-20, usw.), dann gibt es dazu die Funktion “range”, aufruf mit
$reihenfolge = range(1,20);
Dabei erhält man ein Array mit Werten von 1 – 20.
Die alternative ist, das ganze “manuell” zu erledigen, sprich in unserem Beispiel 1-20 wäre das:
$reihenfolge=array();
for ($i=1;$i<=20;$i++)
  array_push($reihenfolge,$i);
Meine ursprüngliche Fassung war Nummer 2 bis ich auf die Funktion “range” stieß. Und die muss ich natürlich gleich ausprobieren und Performance-Tests machen. “Muss doch mit einer PHP-Funktion schneller sein wie mein kindlich-naiver Ansatz!”, denke ich mir so, denn eine Zeile gegen 3 Zeilen, dazu noch von PHP-Spezialisten verfasst und – wahrscheinlich – optimiert bis zum maximal Möglichen, dass _muss_ doch schneller gehen!
Aber was ist nun schneller, range oder for?
Meine Tests habe ich mit dem Zend Studio vorgenommen, hier das Durchschnittliche Ergebnis von vielen Messungen:
range
for
1-20
0.047ms
0,006ms
Hätte ich persönlich nicht vermutet, aber meine Kindlicher Ansatz ist wirklich schneller und zwar im Durchschnitt 7x schneller.

[UPDATE 28.06.2010]

Danke an Daniel und seine "Nachuntersuchung" meines Artikels, dabei habe ich noch einen Fehler in meiner Auswertung gefunden, der mich wirklich zu meinem gezeigten Ergebnis bringt.

Zur Überprüfung habe ich nochmal einen eigenen Code geschrieben, der range, array_push und [] überprüft und aufzeit: range ist wirklich um ein vielfaches schneller wie die beiden anderen Methoden! Daniel, du hast ja recht ;)

Hier mal der Testcode:

$anzahl_der_werte = 99999;

$start1=microtime(1);
$stack1=array();
for ($i=1;$i<=$anzahl_der_werte;$i++)
 array_push($stack1,$i);
$ende1=microtime(1);

$stack2=range(1,$anzahl_der_werte,1);
$ende2=microtime(1);

$stack3=array();
for ($i=1;$i<=$anzahl_der_werte;$i++)
 $stack3[]=$i;
$ende3=microtime(1);

echo "Anzahl der Durchgaenge: " . $anzahl_der_werte . "\n";
echo "Zeit array_push: " . ($ende1-$start1) . "\n";
echo "Zeit range: " . ($ende2-$ende1) . "\n";
echo "Zeit []: " . ($ende3-$ende2) . "\n";
exit;

Und das Ergebnis:

Anzahl der Durchgaenge: 99999
Zeit array_push: 0.36060690879822
Zeit range: 0.013633966445923
Zeit []: 0.33861804008484

Man sieht also sehr gut, dass range wirklich schneller ist, das ganze hält sich auch bei kleinen und großen Werten, man muss sich also nur merken, dass man bei sowas range nimmt.

Donnerstag, 24. Juni 2010

Algorithmus Wettbewerb: Meine Lösung

Eine super Idee hat Michael in seinem Blog: Eine Programmier-Aufgabe, die es wirklich in sich hat.

Die Aufgabe findet ihr unter dem Link, hier findet sich meine Lösung.

28.06.2010
Das ganze muss auch eine mathematische Lösbarkeit haben, hier mal meine bisherigen Überlegungen:
x = Anzahl der Spieler
p1 = Anzahl der möglichen Platzierungen ohne Partiedopplung (also ohne das ein Spieler mehrfach gegen einen anderen antritt), Brettdopplung nicht berücksichtigt:
p1 = (x²-x)/2 = Summe 1 bis (x-1)

Memo an mich: Mehrfach-Matrix mit Substitution erstellen, Speicherbedarf testen!

24.06.2010

Erste Lösung, nicht hochperformant, aber funktioniert.
Die echo "." Angaben und die variable $neustarts sind nur für mich und könnten in einer finalen Fassung entfernt werden
<?php
$startzeit = microtime(1);
if ($_SERVER['argv'][1]%2!=0)
 die("Nur gerade Eingaben!\n");
$spieler = $_SERVER['argv'][1];
//$spieler = 8;
$bretter = $spieler/2;
$spielplan = array();
$neustarts=0;
$abbruch = $spieler ^ 3;
for ($runde=1; $runde<=$bretter; $runde++)
{
 $rundensatz  = -1;
 $count    = 0;
 while ($rundensatz == -1)
 {
  $count++;
  if ($count > $abbruch)
  {
   $count=0;
   for ($x=1;$x<=($spieler/2);$x++)
    $spielplan[$x] = null;
   $runde=0;
   $neustarts++;
   echo "."; flush();
   break;
  }
  $spielerstack  = generiereSpielerStack($spieler);
  $rundensatz  = besetzeRunde($spielplan,$runde,$spielerstack);
 }
 if ($rundensatz==-1) continue;
 $spielplan[$runde]  = $rundensatz;
}

print_r($spielplan);

$endzeit=microtime(1);
printf("Spieler: %u\n",$spieler);
printf("Bretter/Runden: %u\n",$bretter);
echo 'Benoetigte Zeit: '.($endzeit-$startzeit).'s'."\n";
printf('Benoetigte Neustarts: %s',$neustarts);

exit;

function generiereSpielerStack($spieler)
{
 $stack=array();
 for ($i=1;$i<=$spieler;$i++)
  array_push($stack,$i);
 shuffle($stack);
 return $stack;
}

function besetzeRunde($spielplan,$runde,$spielerstack)
{
 $bretter = count($spielerstack)/2;
 $aktuellerSpieler = array_shift($spielerstack);
 while (count($spielerstack)>0 && is_numeric($aktuellerSpieler))
 {
  if ($brett>$bretter)
  {
   return -1;
  }
  for ($brett=1;$brett<=$bretter;$brett++)
  {
   $opp=0;
   if (brettBesetzt($brett,$runde,$spielplan))
    continue;

   if (hatGespieltAufBrett($aktuellerSpieler,$brett,$spielplan))
    continue;

   if (is_numeric($spielplan[$runde][$brett][0])
    &&
    hatGespieltGegen($aktuellerSpieler,$spielplan[$runde][$brett][0],$spielplan))
    continue;

   if (is_numeric($spielplan[$runde][$brett][0]))
    $opp=1;

   $spielplan[$runde][$brett][$opp]=$aktuellerSpieler;
   $aktuellerSpieler = array_shift($spielerstack);
   if (is_null($aktuellerSpieler))
   {
    return $spielplan[$runde];
   }
   $brett=0;
  }
 }
 if (is_numeric($aktuellerSpieler))
  return -1;
 else
  return $spielplan[$runde];
}

function brettBesetzt($brett,$runde,$spielplan)
{
 return (is_numeric($spielplan[$runde][$brett][0]) && is_numeric($spielplan[$runde][$brett][1]));
}

function hatGespieltGegen($spieler1, $spieler2, $spielplan)
{
 for ($i=1;$i<=count($spielplan);$i++)
 {
  if ($spielplan[$i] == null)
   return false;

  for ($j=1;$j<=count($spielplan[$i]);$j++)
  {
   if ( ($spielplan[$i][$j][0] == $spieler1 && $spielplan[$i][$j][1] == $spieler2 )
     ||
     ($spielplan[$i][$j][0] == $spieler2 && $spielplan[$i][$j][1] == $spieler1 )
    )
    return true;
  }
 }
 return false;
}

function hatGespieltAufBrett($spieler, $brett, $spielplan)
{
 for ($i=1;$i<=count($spielplan);$i++)
 {
  if ($spielplan[$i] == null)
   return false;

  if ($spielplan[$i][$brett][0] == $spieler || $spielplan[$i][$brett][1] == $spieler )
   return true;
 }
 return false;
}
Verbesserungsvorschläge überaus erwünscht ;)

Syntax Highlighting mit Blogger

Endlich! Mein Blog kann nun auch Syntax Highlight für beliebigen Code und ich kann das ganze mit den Zitaten endlich wegfallen lassen. Dabei ist das ganze recht einfach, ich poste mal, wie ich es gemacht habe. Um Syntax Highlighting mit Blogger hinzubekommen ging ich wie folgt vor:

  1. Runterladen der Quellen des dp.SyntaxHighlighter von dieser Adresse.
  2. Entpacken und auf einen Webspace hochladen, von dem dann der SyntaxHighlighter nachgeladen werden darf (und kann).
  3. Dannach in blogger im Punkt “Design” den Punkt “HTML bearbeiten” aufrufen.
    1
  4. Nun in der Vorlage das öffnende <head>-Tag suchen und dahinter dann diesen Code einfügen. [YOURHOST] müsst ihr selbstverständlich mit eurem Server ersetzen.
    <link href='http://[YOURHOST]/syntaxhighlighter/Styles/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shCore.js'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shBrushPhp.js'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shBrushCss.js'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shBrushJava.js'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shBrushJScript.js'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shBrushSql.js'/>
    <script language='javascript' src='http://[YOURHOST]/syntaxhighlighter/Scripts/shBrushXml.js'/>

    <script language='javascript'> window.onload = function () {
    dp.SyntaxHighlighter.BloggerMode();
    dp.SyntaxHighlighter.HighlightAll('code');
    }
    </script></span>

    2
  5. Ihr müsst selbst entscheiden, welche Sprachen ihr hinzufügen möchtet, auf jeden Fall braucht ihr die .css Datei und die shCore.js!
  6. Um nun das Syntax Highlighting zu benutzen, müsst ihr euren Code in ein spezielles Format bringen, genauer gesagt, ihr müsst es entweder mit einem <pre> oder einer <textarea> umschließen, die Syntax sieht so aus:
    Code...
    Gleiches gilt für die Textarea!
  7. Viel Spaß ….

Mittwoch, 23. Juni 2010

PHP Magazin Jahresabo zu gewinnen

Wer noch eins von zwei Jahresabo’s für das PHP Magazin gewinnen möchte, der muss sich beeilen, den die Aktion von PHPPerformance.de endet heute um 15:00 Uhr.

Dienstag, 15. Juni 2010

Blog WM 2010

Blogprojekt startet die Blog WM 2010 und dieses Blog ist dabei.
Derzeitige Platierung: Vorrunde 1 – Duell 3
Gewinnen könnt auch ihr was, jeder der abstimmt und einen Kommentar bei Blogprojekt postet, kommt in die Verlosung.

Blog-WM 2010
Ich freue mich über jede Stimme und sage Danke an alle Voter!

Mittwoch, 9. Juni 2010

Autocomplete funktioniert nicht in Zend Studio 7.2

Größere Projekte lassen sich ja in Zend Stuio bzw. eclipse recht gut bearbeiten. Mein Problem war nun, dass plötzlich in allen Projekten das autocomplete-Feature überhaupt nicht mehr funktionierte. Lediglich das Popup öffnete sich, allerdings leer.

Die Lösung ist diese: Sucht in eurem Workspace nach dieser Datei:

Zend/workspaces/<your workspace name>/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.dltk.ui.prefs

und löscht diese.

Dannach das Zend Studio neu starten und autocomplete ist wieder aktiv.

Gefunden in diesem Thread, danke: http://forums.zend.com/viewtopic.php?f=59&t=6317

Dienstag, 8. Juni 2010

Mein eclipse

Ich möchte euch hier mal einen Screenshot meines eclipse vorstellen.

Zu sehen ist aktuell meine Bearbeitung einer Einsendeaufgabe für’s Studium an meinem Rechner zu Hause.

studiendesktop

Links oben der “Package/Klassen Explorer”, mit dessen Hilfe sich schnell navigieren läßt. Drunter die “Outline”, mit deren Hilfe man schnell Funktionen, Klassen und Variablen erkennt. Darunter die “Progress” Anzeige, auch nützlich um zu sehen, woran das aktuelle Kompilat mal wieder “klemmt”.

Mittig – logisch – die Quellcodeansicht. Darunter dann die “Problems”, woran man schnell erkennt, wo man sich vertippt hat.

Rechts sind 2 Bereiche, die linke ist 2-fach unterteilt, oben die “Console”, wo man schnell Ausgaben ablesen kann, die man mittels “System.out.println” Aufrufe erstellt; darunter dann “Declarations” und “Properties” – diese dienen zumeist bei Entwicklung mittels RAD im Visual Editor.

Ganz rechts die “JavaDoc” ansicht. Befinde ich mich im Quellcode über einem Keyword, so bekomme ich dann schnell die aktuelle JavaDoc angezeigt … sehr hilfreich.

Und wie sieht euer eclipse aus?