Guess what’s happening – Folge 1
Irgendwo habe ich vor ’ner Weile im Netz eine Rubrik auf einem Blog gefunden die ungefähr „Guess what’s happening“ hieß. Irgendwie hat mich die Idee fasziniert eine Reihe zu machen in der man einfach mal ein paar PHP Code-Snippets aufschreibt, die sich vielleicht anders verhalten, als man denkt. Heute möchte ich damit starten und habe drei kurze Code-Snippets zusammengestellt. Die Profis von euch werden wahrscheinlich eh auf Anhieb sehen, was passiert.
define( MY_VAR, 'hallo' );
define( MY_VAR, 'welt' );
echo MY_VAR;
Natürlich gibt dieses Codefragment ‚hallo‘ aus, denn nach dem ersten Durchgang ist die MY_VAR Konstante gefüllt und kann dann beim zweiten define durch den Wert ersetzt werden. Ich finde es schon fast einen WTF, dass PHP falls eine Konstante nicht existiert den String des Namens übernimmt, aber darüber hatten wir glaube ich schon mal geredet. Vergesst also nie die die Anführungszeichen.
$array = array( 'rot', 'gruen', 'blau');
implode( '-', $array );
implode( $array, '-' );
Einmal die Methode mit Array als erstes und dann die gleiche Methode mit dem Glue als erstes. Man möchte doch eigentlich glauben, dass eine von den beiden Varianten einen Fehler wirft. Nö, nichts da. Beide funktionieren … natürlich aus historischen Gründen. Zum Glück ist diese Art Software zu entwickeln nicht normal geworden. In PHP kann man wirklich so einige Schweinereien umsetzen. Auch im Userspace.
Das dritte Guess what’s happening ist nicht wirklich ein WTF, sondern viel mehr etwas, was mich schon eine Weile interessiert hat (nicht dass man es mal brauchen könnte). Was passiert eigentlich wenn ich eine Klasse gehen zwei Interfaces implementiere, die eine Methode gleich haben. Sowas wie:
interface a
{
public function doSth( );
}
interface b
{
public function doSth( );
}
class C implements a, b
{
public function doSth( )
{
}
}
$class = new C;
Keine Ahnung, ob das mal sinnvoll sein könnte, aber PHP verhindert es mit der Fehlermeldung: Can’t inherit abstract function b::doSth() (previously declared abstract in a). So das war’s auch schon wieder für heute. Ich würde mich freuen, wenn ihr auch solche GWH’s habt und sie mir per E-Mail zukommen lassen könntet. Dann machen wir einen schönen zweiten Teil draus.
ICh glaube du hast einen Fehler gemacht:
Natürlich gibt dieses Codefragment ‘hallo’ aus, denn nach dem ersten Durchgang ist die MY_VAR Konstante gefüllt und kann dann beim zweiten define durch den Wert ersetzt werden.
Das sollte wohl nicht durch den Wert ersertz werden;)
Guten Morgen Nils,
dein zweites Beispiel wirft wohl eher eine Fehler der Art: E_PARSE, unexpected ‚)‘ 🙂
implode( ‚-‚, $array ) );
implode( $array, ‚-‚ ) );
Beste Grüße nach Hamburg
Manuel
@ragtek: Irgendwie versteh ich deine Anmerkung gerade nicht.
Du schreibst:
_______________________________________________
Natürlich gibt dieses Codefragment ‘hallo’ aus, denn nach dem ersten Durchgang ist die MY_VAR Konstante gefüllt und kann dann beim zweiten define durch den Wert ersetzt werden.
_______________________________________________
Das ist so aber nicht wahr.
Die MY_VAR Konstante wird in der 1. Zeile definiert und dadurch kann sie nicht in der 2. Zeile ersetzt werden (was du aber geschrieben hast)
Wenn es so währe wie du es geschrieben hast (sie wird ersetzt)würde sie welt zurückgeben und nicht hallo
Jetzt etwas verständlicher?
Daniel
Danke für den Beitrag, neues Futter für unsere „Was passiert Runde“ im Büro 🙂
Cooler Artikel, danke!
P.S.: Kleiner Tippfehler: Bei den implode() Aufrufen ist jeweils eine schliesende Klammer zu viel.
was dem ein oder anderen auch bekannt vorkommen dürfte:
count( ‚warum nur so wenig‘ ) === 1
Beim ersten Beispiel gibt es auch Seiteneffekte die man zunächst nicht erwartet. Im ersten Define wird MY_VAR auf ‚hallo‘ gesetzt. Beim zweiten dann ‚hallo‘ auf ‚welt‘ (da MY_VAR sofort durch hallo ersetzt wird). Deine Formulierung bringt das finde ich nicht deutlich raus.
Code zum selbst testen:
define( MY_VAR, ‚hallo‘ );
define( MY_VAR, ‚welt‘ );
echo MY_VAR;
print_r(get_defined_constants());
liefert:
…
[MY_VAR] => hallo
[hallo] => welt
..
Hmm, das mit den Interfaces stört mich jetzt aber extrem… Interfaces wären ja dazu da, um MultipleInheritance zu erlauben -.- Siehe dazu Java (ohoh, Hassmails 🙂 )
Das mit den Interfaces ist mir auch neu. Hätte schwören können..
Die Besonderheit an Bsp. 1 verstehe ich nicht wirklich. Und 2 ist ein alter Hut. Übrigens einer der wenigen Altlasten dieser Art in PHP.
@Peter,
jetzt habe ich gerade auch ein wenig mit Konstan rum gespielt und mir ist ein Fehler bei deinem und Nils Skript aufgefallen. define erwartet nämlich als ersten Parameter einen String. Auch wenn PHP nach dem es keine Konstane mit diesem Namen findet einen String daraus macht ist es doch „falsch“ und liefert bei error_reporting = E_ALL auch einen Notice.
Wenn man also einen String benutz, wo einer hin soll, wird der WTF Effekt ein wenig abgeschwächt! 😉
@ragtek, guck dir mal den Komentar von Peter an – ich habe an der von dir beschrieben Stelle beim ersten Lesen auch einen Fehler gesehen! 😉
@David: wieso hassmails? in java gibt es doch auch probleme, zwei interfaces mit gleichem methodennamen zu implementieren.
siehe abschnitt „Name collisions when combining interfaces“:
http://www.linuxtopia.org/online_books/programming_books/thinking_in_java/TIJ310_001.htm
da müsste man schon auf c# zurückgreifen, wo syntaktisch explizit methoden eines ganz bestimmten interfaces implementiert werden können.
Coole Rubrik, ich hatte mir auch schonmal vorgenommen solche Stellen mal zu sammeln. Beim nächsten mal denk ich sicher dran 😉
Das mit den Konstanten war leider wirklich etwas missverständlich, aber wir haben es in den Kommentaren ja aufklären können 🙂
Dazu gleich eine Frage, normal benutze ich Konstanten in meinen Konfigurationsdateien. Hin und wieder brauche ich aber auch mal ein Array. Das kann ich natürlich serialisieren, aber ist das auch eine saubere Lösung? Hab auch schon oft gesehen das Variablen dann mit global an den zu nutzenden Stellen herbeigezaubert werden. Irgendwie macht das auf mich aber einen unsauberen Eindruck.
Wie würdet ihr das lösen?
Bzgl. der Problematik mit den Interfaces…
Soweit ich weiß ist das in Sprachen wie C#, die das Überladen von Methoden unterstützen, kein Problem. PHP unterstützt das jedoch nicht. In dem von dir genannten Beispiel sollte es auch für PHP kein Problem sein, die beiden Interfaces zu verwenden, da die zwei Methoden die gleiche Signatur haben. Wenn aber ein Interface die Methode doSth mit zwei Argumenten und das andere Interface doSth mit vier Argumenten definiert, wie willst du das in PHP umsetzen? In C# sollte es kein Problem sein: du implementierst einfach beide Methoden und überlädst sie. In C# hast du aber auch manchmal probleme, nämlich dann, wenn sich die Methoden lediglich durch den Return-Type unterscheiden (eine Methoden liefert int, die andere bool oder auch gar nichts).
Das, was ich bzgl. C# gestern geschrieben habe, stimmt nicht ganz. Haben die Methoden der zwei Interfaces eine unterschiedliche Signatur, reicht eine implizite Implementierung. Haben sie aber, wie im PHP Fall oben, eine identische Signatur, so muss man in C# beide Methoden implementieren und explizit schreiben, welche zu welchem Interface gehört. Somit kann man auch Methoden implementieren, die sich alleine durch den Rückgabewert unterscheiden. Aber nun genug zu C#. 🙂