Schlagwort: PHP

PHP-Funktionen in C# 👍 👎

Da ich sehr häufig von (bestimmt bald ehemaligen Smiley: winking) PHP-Entwicklern gefragt werde, wie sich bestimmte Sachen in C# lösen lassen, habe ich mir überlegt, dies ein wenig koordinierter anzugehen.

Deshalb gibt es ab sofort eine passende (Pseudo-)Kategorie "PHP-Funktionen in C#" dazu, welche unregelmäßig um weitere Funktionen ergänzt werden soll. Vorschläge nehme ich gerne entgegen.

Hashing in C# und PHP 👍 👎

Den meisten PHP-Entwicklern sind die beiden Funktionen md5(…) und sha1(…) geläufig. Diese liefern zu einer übergebenen Zeichenkette einen Streuwert ("Hash") in hexadezimaler Darstellung. Zu diesem Zweck gibt es in C# die beiden Klassen MD5CryptoServiceProvider und SHA1CryptoServiceProvider.

Diesen Klassen kann man über die ComputeHash-Methode unter anderem ein byte-Array übergeben und bekommt daraufhin ein solches zurück, welches den Hash darstellt. Da wir es in der Praxis aber doch meist einfach nur mit Zeichenketten und u. U. auch mit verschiedenen Hash-Algorithmen (z. B. MD5, SHA1) zu tun haben, möchten wir das Ganze in eine komfortable generische Erweiterungsmethode für Zeichenketten verpacken:
Methode implementieren
0102030405060708
public static string GetHash<T>(this string str) where T : HashAlgorithm, new() {    using(T hashProvider = new T()) {          // Streuwert berechnen        byte[] hash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(str));
return Encoding.UTF8.GetString(hash); }}
Für diejenigen, denen die Arbeit mit generischen Typen (noch) nicht geläufig ist, werde ich in Kürze auch noch einen etwas ausführlicheren Beitrag zu diesem Thema verfassen.

Die Rückgabe dieser Methode dürfte nun jedoch leider noch gar nicht dem entsprechen, was viele erwarten – die hexadezimale Schreibweise wie in PHP, so dass diese Ausgaben insbesondere nicht kompatibel zueinander für Vergleiche sind, was die Interoperabilität natürlich massiv beeinträchtigt. C# liefert standardmäßig nämlich das, was bei den entsprechenden PHP-Funktionen mit dem Parameter $raw_output erhältlich ist.

Da die hexadezimale Darstellung jedoch tatsächlich häufig praktikabler ist, stützen wir uns ausnahmsweise ( Smiley: winking) auf diese Vorgehensweise und bringen C# zu diesem – unter anderem von PHP gewohnten – Verhalten:
Methode implementieren (hexadezimale Rückgabe)
0102030405060708
public static string GetHash<T>(this string str) where T : HashAlgorithm, new() {    using(T hashProvider = new T()) {          // Streuwert berechnen        byte[] hash = hashProvider.ComputeHash(Encoding.UTF8.GetBytes(str));
return BitConverter.ToString(hash).Replace("-", String.Empty).ToLower(); }}
Jetzt liefert unsere Erweiterungsmethode für C# exakt das gleiche Ergebnis wie PHP das standardmäßig macht und kann darüber hinaus besonders einfach und flexibel auf jeder Zeichenkette verwendet werden:
Methode verwenden
01
string hashTest = "test".GetHash<SHA1CryptoServiceProvider>();
Durch Übergabe der gewünschten Implementierung als Typparameter erhalten wir nun direkt das Ergebnis.

Index-basierter Zugriff auf Objekte in C# (und PHP) 👍 👎

Manchmal kann es sinnvoll (oder zumindest bequem oder intuitiv) sein, auf ein Objekt im Stile eines Feldes zugreifen zu können. Für das folgende Beispiel zu diesem Thema möchte ich kurz einen Anwendungsfall aus meiner Arbeit beschreiben.

Als ISP müssen wir bei Domains des Öfteren mit sog. "Handles" umgehen. Grob umrissen handelt es sich dabei um einen Kontakt-Datensatz für eine Domain. Darin abgelegt werden beispielsweise der Name, die Anschrift und – je nach TLD – auch noch div. andere Daten.

Im einfachsten Fall verwendet man zur Ablage dieser Informationen also ein assoziatives Feld (in C# z. B. ein generisches Dictionary) als Eigenschaft des Objekts:
"Handle"-Klasse
010203040506
public class Handle {    public Dictionary<string,string> HandleFieldValueList  {        get;        set;    }}
Den Umgang mit derartigen Datenfeldern habe ich zwar schon einmal relativ ausführlich beschrieben, dennoch möchten wir auch hier erst einmal das Objekt mit Daten füllen:
Daten hinzufügen
010203040506070809
Handle ich = new Handle() {      // Feldwerte    HandleFieldValueList = new Dictionary<string,string>() {        {"firstName", "Holger"},        {"lastName", "Stehle"}    }};
// ich.HandleFieldValueList["firstName"] enthält "Holger" etc.
Wie bereits angedeutet, können wir nun wie erwartet auf die entsprechenden Daten zugreifen. In einem solchen Fall – in dem die einzelnen Werte schließlich das Handle an sich ausmachen – wäre es doch aber auch praktisch, diesen Index-basierten Zugriff direkt auf dem Objekt durchführen zu können. Und genau dies ist mit C# ganz einfach möglich. Dazu müssen wir die Klasse wie folgt erweitern:
Indexer ergänzen
01020304050607080910111213141516171819
public class Handle {      // Indexer (-> Feldwerte)    public string this[string fieldName] {        get {            return this.HandleFieldValueList[fieldName];        }        set {            this.HandleFieldValueList[fieldName] = value;        }    }
// Feldwerte public Dictionary<string,string> HandleFieldValueList { get; set; }}
// ich["firstName"] enthält "Holger" etc.
Dies veranschaulicht die Implementierung eines sog. Indexers, welcher sich grundlegend wie eine Eigenschaft verhält. Der hauptsächlich interessante Teil string this[string fieldName] besagt, dass ein Index-basierter Zugriff auf die Instanz (→ this) mit einem Index (→ fieldName) des Typs string einen string liefert und definiert im Stile eines Akzessors, wie genau dies geschieht. Und schon können wir (wie im Code angedeutet) wie erhofft darauf zugreifen.

Indexer können auch überladen werden, so dass z. B. zusätzlich auch ein Zugriff mit numerischem Index ermöglicht werden kann. Zuletzt gilt zu beachten: Es handelt sich hierbei lediglich um eine etwas kompaktere Schreibweise für etwas, was sowieso möglich wäre. Dennoch gibt es – wie ich persönlich finde – interessante Einsatzmöglichkeiten hierfür. Der konkrete Nutzen ist also im Einzelfall abzuwägen.

Um derartiges Verhalten in PHP zu ermöglichen, muss die Klasse die Schnittstelle ArrayAccess implementieren. Ein Beispiel zur Umsetzung findet sich z. B. in der offiziellen Dokumentation.

Datenfelder in C# und PHP 👍 👎

Da ich regelmäßig – insbesondere von PHP-Entwicklern – gefragt werde, wie sich das dort allseits beliebte Array in C# verwenden lässt, möchte ich dazu eine kleine Gegenüberstellung präsentieren.

Zuerst einmal sollte festgestellt werden, dass Arrays unter PHP sehr vielseitig eingesetzt werden, wofür andere Programmiersprachen (wie beispielsweise C#) jeweils eigens optimierte Datenstrukturen vorsehen. Nicht zu vergessen ist natürlich ganz allgemein die unter C# strengere Typisierung.

Wir beginnen die Beispiele demnach also erst einmal mit einfachen Listen und gehen schließlich auch auf mehrdimensionale und assoziative Felder ein.
Liste von Zeichenketten: PHP
010203
$data = ["Ab", "Cd", "Ef"];
$data[] = "Yz";
Liste von Zeichenketten: C# (nativ)
01
string[] data = {"Ab", "Cd", "Ef"};
Es gibt jedoch noch eine elegantere Lösung: Generische Container. Hierbei handelt es sich um vom konkreten Datentyp abstrahierte Mechanismen zur Sammlung und Verwaltung von Daten. Sehen wir uns also das o. g. Beispiel mit Hilfe der generischen List-Klasse in C# an:
Liste von Zeichenketten: C# (generisch)
010203
List<string> data = new List<string>() {"Ab", "Cd", "Ef"};
data.Add("Yz");
Durch den Aufruf entsprechender Instanzmethoden können wir dadurch sehr komfortabel neue Daten hinzufügen, den Inhalt sortieren und natürlich auch per LINQ darauf operieren. Dank Implementierung eines sog. Indexers ist im Übrigen auch bei dieser Variante der gewohnte null-basierte Zugriff per Index z. B. per data[0] möglich.

Gehen wir nun also einen Schritt weiter und stellen mehrdimensionale Felder gegenüber:
Mehrdimensionales Feld: PHP
010203040506
$data = [    ["Ab", "Cd"],    ["Ef", "Gh"]];
$data[] = ["Wx", "Yz"];
Mehrdimensionales Feld: C# (nativ)
01020304
string[,] data = {    {"Ab", "Cd"},    {"Ef", "Gh"}};
Mehrdimensionales Feld: C# (generisch)
010203040506
List<List<string>> data = new List<List<string>>() {    new List<string>() {"Ab", "Cd"},    new List<string>() {"Ef", "Gh"}};
data.Add(new List<string> {"Wx", "Yz"});
Zum Schluss sollen natürlich noch assoziative Felder erwähnt werden, welche wir in C# mit Hilfe eines Dictionary umsetzen:
Assoziatives Feld: PHP
010203040506
$data = [    'FirstName' => "Holger",    'LastName' => "Stehle"];
$data['City'] = "Berlin";
Assoziatives Feld: C#
0102030405060708
Dictionary<string,string> data = new Dictionary<string,string>() {    {"FirstName", "Holger"},    {"LastName", "Stehle"}};
data.Add("City", "Berlin"); // – oder auch -data["City"] = "Berlin";
Zum Durchlaufen eines solchen Feldes in C# bietet sich die Verwendung der KeyValuePair-Struktur an:
Assoziatives Feld durchlaufen: C#
01020304
foreach(KeyValuePair<string,string> entry in data) {    // entry.Key: "FirstName", "LastName" und "City"    // entry.Value: "Holger", "Stehle" und "Berlin"}
Das soll es für den Moment auch erst einmal gewesen sein, zukünftig möchte ich jedoch noch ein paar derartiger Gegenüberstellungen durchführen. Insbesondere auch auf die generische Entwicklung unter C# werde ich noch gesondert in weiteren Beiträgen eingehen.

12

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche