phpcpd ist ein Copy/Paste Detector (CPD) für PHP Quellcode und stammt von Sebastian Bergmann, der auch PhpUnit programmiert hat. Das Tool kann als Pear-Paket installiert werden.
pear config-set auto_discover 1
pear install pear.phpunit.de/phpcpd
phpcpd ist ein Copy/Paste Detector (CPD) für PHP Quellcode und stammt von Sebastian Bergmann, der auch PhpUnit programmiert hat. Das Tool kann als Pear-Paket installiert werden.
pear config-set auto_discover 1
pear install pear.phpunit.de/phpcpd
Auf der Seite PHP Benchmark gibt es eine kleine Auflistung von PHP Optimierungen, die ganz gelungen sind. Natürlich ist die Optimierung von Code bis auf die letzte Zeile übertrieben, aber es schadet nicht ein paar Regeln zu beachten.
Im ersten Test wird der Einsatz des Referenzierungsoperators & geprüft. Als Ergebnis kommt heraus, dass bei eindimensionalen Arrays der Zugriff schneller erfolgt als bei mehrdimensionalen Arrays.
$value = &$simpleArray[$i]; // Laufzeit schneller $value = $simpleArray[$i]; // als diese Variante
Im Gegenzug zu mehrdimensionalen Arrays:
$value = &$bigArray[$a][0][0][0] // Laufzeit langsamer $value = $bigArray[$a][0][0][0] // als diese Variante
Zwischen den Varianten gibt es keinen nennenswerten Laufzeitunterschied. Lediglich bei den Vergleichen mit Typisierung (===) gab es einen kleinen Vorteil.
Bei reine Strings macht es schienbar keinen Unterschied, ob einfache oder doppelte Anführungszeichen verwendet werden. Leider stimmt das nur, solange keine Variablen innerhalb des Strings ersetzt werden müssen. Ich habe das mal ausprobiert:
"aa $x aaaa $x aaaa $x a"; // 0.000581 'aa $x aaaa $x aaaa $x a'; // 0.000160 'aa '. $x. ' aaaa '. $x. ' aaaa '. $x. ' a'; // 0.000565 echo 'aa ', $x, ' aaaa ', $x, ' aaaa ', $x, ' a'; // 0.000378
Auch hier gab es keinen nenneswerten Sieger. Die Funktion in_array ist teurer als die anderen zwei und sollte nur auf existierenden Variablen aufgerufen werden.
is_array($gibtsNicht); // langsam (und PHP Notice: Undefined variable) isset($gibsNicht) && is_array($gibtsNicht) // besser
Ein Funktionsaufruf im Schleifenkopf ist keine gute Idee. Die vielen Aufrufe kosten sehr viel Laufzeit.
<code>for ($i=0; $i<count($x); $i++);</code> // ganz schlecht $count=count($x); for ($i=0; $i<$count; $i++); // super
Außerdem kostet der Befehl list ebenfalls sehr viel Laufzeit. Meiner Meinung nach sollte man diese Funktion nicht verwenden, da der Code dadurch schlecht lesbar wird:
while(list($key) = each($hash))... // langsam und schlecht lesbar foreach($hash as $key=>$value)... // schnell
Gegen Ende des Beitrags wurde nochmal die Schleifen bzw. die Modifikation des Array betrachtet, über das iteriert wird. Das die for-Schleife in folgender Variante so schlecht abschneidet, hat mich doch sehr verwundert:
// 425% foreach($aHash as $key=>$val) $aHash[$key] .= "a"; // 100% $key = array_keys($aHash); $size = sizeOf($key); for ($i=0; $i<$size; $i++) $aHash[$key[$i]] .= "a";
Das schlechte Ergebnis wird aber durch die Operation .= verursacht, die den bestehenden Wert mit “a” konkateniert. Mit einer reinen Zuweisung läuft die foreach-Schleife sehr performant. Ich habe zusätzlich folgendes ausprobiert:
foreach($aHash as $key=>$val); // 0.00001 foreach($aHash as $val); // 0.000007 foreach($aHash as $key=>&$val); // 0.00023 foreach($aHash as &$val); // 0.00024 foreach($aHash as $key=>$val) $aHash[$key] .= "a"; // 0.00024 (ursprüngliche Variante) while(list($key) = each($aHash)) $aHash[$key] .= "a"; // 0.00008 (ursprüngliche Variante)
Anmerkung: Das Array bestand ebenfalls aus 100 Elemente mit einer Schlüssellänge von 24byte und einem Wert mit 10k pro Eintrag.
Ich schätze, dass es damit zusammenhängt, dass die foreach-Schleife intern mit einer Kopie des Array arbeitet. Notiz an mich: Diesen Artikel mal genauer lesen: PHP internals: When does foreach copy?
Ich glaube, dass die wenigsten Ergebnisse praxisrelevant sind. Bester Tip ist, dass man in Schleifenkopfen keine Funktionen aufrufen soll bzw. in Schleifen allgemein auf Funktionsaufrufe achten soll. Ein super Artikel fand ich auf ircmaxell’s blog im Artikel On Optimization in PHP. Code soll in erster Linie lesbar und somit besser warten sein. Außerdem wird dort die 90/10-Regel von R. Pattis erwähnt: “90% of a program’s execution time is spent in only 10% of its code.”. Die Kunst des Optimieres ist es also, die 10% des Codes in angemessener Zeit ausfindig zu machen…
Am 15.02.2012 wurde das Contao 2.11.0 Release veröffentlicht. Das Release ist das erste für die ein “Long-Term-Support” gilt, also mindestens 18 Monate gepflegt wird. Es wurde kräftig an Contao gearbeitet. Die wichtigsten Änderungen sind nachfolgend beschrieben:
$GLOBAL['TL_CSS'][] = 'mystyle.css|screen|static';
{{page}}Ein Update von Contao 2.10 auf 2.11 funktionierte problemlos.
Heute war ich auf der Suche nach eine Lösung für einen Cron Manager unter Windows. Der ein oder andere kann jetzt mit dem Argument kommen, dass man ja mit den “geplanten Tasks”, “Aufgabenplanung”, “Task Scheduler” oder “Scheduled Tasks” (je nach Windows Version) gemacht werden kann – das ist natürlich richtig. Aber wie siehts mit einer Ausführungshistorie aus? – Ja, auch möglich, wenn man das aktiviert. Geht auch eine Email, falls der Job fehlschlägt? – Ja, auch das ist möglich, sofern der SMTP-Server korrekt konfiguriert ist. Jetzt die Preisfrage: Können auch andere Nutzer (Nicht-Administratoren) Jobs/Crons anlegen? …mhh… schwer? Oder wie wäre es mit einer Statusanzeige fürs Intranet? Ganz nützlich wäre auch das Ausführen von Cronjobs auf verschiedenen Servern, jedoch mit zentraler Administration. Wir sehen, an diesem Punkt stoßen wir mit den Windows Bordmitteln an Grenzen.
Der Titel klingt ja schon kriptisch, aber mal von vorne… über die Robots-Anweisungen lassen sich die “guten” Suchmaschinen bzw. dessen Crawler beeinflussen. Beispielsweise kann man bestimmte Seiten von der Indizierung ausschließen indem man im Wurzelverzeichnis einfach eine robots.txt anlegt und dort ein paar Regeln reinschreibt.
Beispiel:
disallow: [path]
Eine Auflistung aller Möglichkeiten findet sich auf der Seite Controlling Crawling and Indexing.
Außerdem gibts das ganze auch als Meta-Tag-Anweisung:
<meta name="robots" content="noindex" />
Schließlich kann man das ganze auch als HTTP-Header-Anweisung definieren:
X-Robots-Tag: noindex
In PHP kann dies einfach realisiert werden:
header('X-Robots-Tag: noindex');
Da der Google Crawler immer besser wird und mittlerweise auch URLs in Javascript folgt, ist diese Anweisung ggf. bei einem AJAX-Aufruf sinnvoll.
Leider funktionieren Conditional Commands mit TemplaVoila nicht, da das abschließende HTML-Kommentar nicht ausgegeben wird. Beispiel:
<!--[if lt IE 9]><script src="..."></script><![endif]-->Bis das funktioniert, löse ich das über eine TypoScript Anweisung:
page.headerData.100 = HTML page.headerData.100.value = <!--[if lt IE 9]><script src="..."></script><![endif]-->
Hier ein Snippet, wie man sich an einem Proxy über CURL authentifizieren kann:
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'http://www.foo.bar'); curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); curl_setopt($ch, CURLOPT_PROXY, 'proxy:8080'); curl_setopt($ch, CURLOPT_PROXYPORT, 8080); curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'DOMÄNE\benutzer:password'); curl_setopt($ch, CURLOPT_TIMEOUT, 20); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); curl_setopt($ch, CURLOPT_REFERER, 'http://myreferer.de'); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla...'); $result = curl_exec($ch); $info = curl_getinfo($ch); $error = curl_error($ch); curl_close($ch);
Während der Modulentwicklung kommt man schnell an den Punkt, wo man verschiedene Einstellungen zu einem Contao Modul hinterlegen möchte. Das kann eine Weiterleitungsseite sein, ein Text oder ein x-beliebiger Wert aus einem Auswahlfeld oder ähnliches. Jeder Eintrag in den Modulen einer “Theme” entspricht einem Datensatz in der Tabelle tl_module. Dort werden auch alle Einstellungen zu einem Modul hinterlegt.
Um eine dieser bestehenden Spalten in einem Modul nutzen zu können, muß man in der DCA eine Zeile ergänzen:
$GLOBALS['TL_DCA']['tl_module']['palettes']['mymodule'] = '{title_legend},name,headline,type,customLabel';
Schon steht im Modul ein einfaches Textfeld zur Verfügung. Da diese Einstellung bereits von Contao verwendet wird, gibt es bereits eine Felddefinition und eine Übersetzung für die Einstellung customLabel. Damit wir keine neue Spalte in der tl_module anlegen müssen, können wir das Feld für etwas anderes “mißbrauchen”. Ich will nur demonstrieren, wie man Änderungen vornehmen kann, die im Prinzip auch bei einem neuen Feld notwendig sind.
Die Übersetzung wird beispielsweise folgendermaßen gesetzt bzw. überschrieben:
$GLOBALS['TL_LANG']['tl_module']['customLabel']=array('View', 'Please select a view type.');
Den Feldtyp können wir folgendermaßen beeinflussen:
$GLOBALS['TL_DCA']['tl_module']['fields']['customLabel'] = array( 'label' => &$GLOBALS['TL_LANG']['tl_module']['customLabel'], 'inputType' => 'select', 'options' => array(1=>'Overview', 2=>'Detail') );
Somit haben wir jetzt folgendes im Backend erreicht:
Eines sollte jedoch klar sein, wenn man bestehende Felddefinitionen verändert: Auch in den Modulen, in den die Einstellung bereits verwendet wird, kann unter Umständen die Veränderung greifen. Das wiederum hängt von der Reihenfolge ab, wie die Module abgearbeitet werden (alphabetisch).
Nachfolgend eine komplettes Beispiel mit jQuery und der neuen Fullscreen-API ein HTML-Element im Vollbild-Modus anzuzeigen. Funktioniert nur in den neusten Browser von Safari, Firefox und Chrome und sieht auch nur im Firefox gut aus… aber hier gehts einfach nur um die Funktion.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script type="text/javascript" src="jquery.js"></script> <style>
.white { font-family:verdana; margin-top:200px; } .white div { background-color:white; width:50%; margin:auto; -moz-border-radius: 5px; border-radius: 5px; -moz-box-shadow: 5px 5px grey; -webkit-box-shadow: 5px 5px grey; box-shadow: 5px 5px grey; padding:25px; } .hidden { display:none; }
</style> </head> <body> <div id="fullscreen-container"> <div> <div> Here is your Fullscreen! </div> </div> </div> <p> <a href="#" id="fullscreen-link">Show me fullscreen container...</a> </p> <script type="text/javascript">
//<![CDATA[ (function($) { $.fn.extend({ fullscreen:function(params) { var conf = {}; $.extend(conf, params); return $(this).each(function() { var e=$(params); var element=e[0]; $(this).click(function() { e.removeClass('hidden'); if(element.requestFullScreen) { element.requestFullScreen(); jQuery(document).bind("fullscreenchange", function() { if(!document.fullScreen) e.addClass('hidden') }); } else if (element.mozRequestFullScreen) { element.mozRequestFullScreen(); jQuery(document).bind("mozfullscreenchange", function() { if(!document.mozFullScreen) e.addClass('hidden') }); } else if (element.webkitRequestFullScreen) { element.webkitRequestFullScreen(); jQuery(document).bind("webkitfullscreenchange", function() { if(!document.webkitIsFullScreen) e.addClass('hidden') }); } }); }); } }); })(jQuery); jQuery('#fullscreen-link').fullscreen('#fullscreen-container'); //]]> </script>
</body> </html>