it-swarm-eu.dev

Geben Sie Casting-Variablen in PHP ein. Was ist der praktische Grund dafür?

PHP hat, wie die meisten von uns wissen, schwache Eingabe . Für diejenigen, die dies nicht tun, sagt PHP.net:

PHP erfordert (oder unterstützt) keine explizite Typdefinition in der Variablendeklaration. Der Typ einer Variablen wird durch den Kontext bestimmt, in dem die Variable verwendet wird.

Ich liebe es oder ich hasse es, PHP wandelt Variablen im laufenden Betrieb neu um. Der folgende Code ist also gültig:

$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)

Mit PHP können Sie auch eine Variable explizit umwandeln, wie folgt:

$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"

Das ist alles cool ... aber für mein Leben kann ich mir keinen praktischen Grund dafür vorstellen.

Ich habe kein Problem mit der starken Eingabe in Sprachen, die dies unterstützen, wie Java. Das ist in Ordnung und ich verstehe es vollkommen. Ich bin mir auch der Nützlichkeit von - Typhinweis in Funktionsparametern bewusst - und verstehe sie vollständig.

Das Problem, das ich beim Typguss habe, wird durch das obige Zitat erklärt. Wenn PHP kann Typen tauschen nach Belieben, kann es dies auch tun, nachdem Sie Besetzung erzwingen einen Typ; und es kann dies tun on-the-fly wenn Sie einen bestimmten Typ in einer Operation benötigen. Das macht folgendes gültig:

$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"

Also, was ist der Punkt?


Nehmen Sie dieses theoretische Beispiel einer Welt, in der benutzerdefinierte Typumwandlungen in PHP sinnvoll sind:

  1. Sie erzwingen die Cast-Variable $foo Als int(int)$foo.
  2. Sie versuchen, einen Zeichenfolgenwert in der Variablen $foo Zu speichern.
  3. PHP löst eine Ausnahme aus !! ← Das würde Sinn machen. Plötzlich liegt der Grund für das benutzerdefinierte Typgießen vor!

Die Tatsache, dass PHP die Dinge nach Bedarf umschaltet, macht den Punkt des benutzerdefinierten Typ-Castings vage. Beispielsweise sind die folgenden zwei Codebeispiele äquivalent:

// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

Ratet mal, wer ein Jahr nach der ursprünglichen Beantwortung dieser Frage die Typografie in einer praktischen Umgebung verwendet hat? Mit freundlichen Grüßen.

Die Anforderung bestand darin, Geldwerte auf einer Website für ein Restaurantmenü anzuzeigen. Für das Design der Site mussten nachgestellte Nullen abgeschnitten werden, damit die Anzeige wie folgt aussah:

Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3

Der beste Weg, diese Verschwendung zu finden, um die Variable als Float umzuwandeln:

$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;

PHP schneidet die nachgestellten Nullen des Floats ab und setzt den Float dann als Zeichenfolge für die Verkettung neu.

45
Stephen

In einer schwach typisierten Sprache gibt es ein Typ-Casting, um Mehrdeutigkeiten bei typisierten Operationen zu beseitigen, wenn der Compiler/Interpreter andernfalls die Reihenfolge oder andere Regeln verwenden würde, um anzunehmen, welche Operation verwendet werden soll.

Normalerweise würde ich sagen PHP folgt diesem Muster, aber von den Fällen, die ich überprüft habe, PHP hat sich in jedem Fall kontraintuitiv verhalten.

In diesen Fällen wird JavaScript als Vergleichssprache verwendet.

String-Konzentration

Offensichtlich ist dies kein Problem in PHP, da es separate String-Verkettung gibt (.) und Addition (+) Operatoren.

JavaScript
var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15

String-Vergleich

In Computersystemen ist "5" häufig größer als "10", da es nicht als Zahl interpretiert wird. Nicht so in PHP, das, selbst wenn beide Zeichenfolgen sind, erkennt, dass es sich um Zahlen handelt, und die Notwendigkeit einer Besetzung beseitigt):

JavaScript
console.log("5" > "10" ? "true" : "false"); // true
PHP
echo "5" > "10" ? "true" : "false";  // false!

Eingabe der Funktionssignatur

PHP implementiert eine reine Typprüfung der Funktionssignaturen, ist aber leider so fehlerhaft, dass es wahrscheinlich nur selten verwendet werden kann.

Ich dachte, ich mache vielleicht etwas falsch, aber ein Kommentar zu den Dokumenten bestätigt, dass andere integrierte Typen als Array nicht in PHP - Funktionssignaturen verwendet werden können - obwohl die Fehlermeldung ist irreführend.

PHP
function testprint(string $a) {
    echo $a;
}

$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
                      //  must be an instance of string, string given" WTF?

Und im Gegensatz zu jeder anderen Sprache, die ich kenne, kann null nicht mehr an dieses Argument übergeben werden, selbst wenn Sie einen Typ verwenden, den es versteht (must be an instance of array, null given). Wie blöd.

Boolesche Interpretation

[ Bearbeiten ]: Dieser ist neu. Ich dachte an einen anderen Fall, und wieder ist die Logik von JavaScript umgekehrt.

JavaScript
console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.
PHP
echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.

Zusammenfassend kann ich mir nur vorstellen, dass ... (Trommelwirbel)

Geben Sie die Kürzung ein

Mit anderen Worten, wenn Sie einen Wert eines Typs haben (z. B. Zeichenfolge) und ihn als einen anderen Typ (int) interpretieren möchten und erzwingen möchten, dass er zu einem der gültigen Wertesätze in diesem Typ wird:

$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties

Ich kann nicht sehen, was Upcasting (zu einem Typ, der mehr Werte umfasst) Sie jemals wirklich gewinnen würde.

Also, während ich mit Ihrer vorgeschlagenen Verwendung der Eingabe nicht einverstanden bin (Sie schlagen im Wesentlichen statische Eingabe vor, aber mit der Mehrdeutigkeit, dass nur wenn es Force-Cast in einen Typ wäre es wirft einen Fehler - was Verwirrung stiften würde), ich denke, es ist eine gute Frage, weil anscheinend Casting sehr wenig Sinn in PHP hat.

32
Nicole

Sie mischen die Konzepte für schwache/starke und dynamische/statische Typen.

PHP ist schwach und dynamisch, aber Ihr Problem liegt im dynamischen Typkonzept. Das heißt, Variablen haben keinen Typ, Werte schon.

Ein 'Typ Casting' ist ein Ausdruck, der einen neuen Wert eines anderen Typs des Originals erzeugt. es macht nichts mit der Variablen (wenn eine beteiligt ist).

Die einzige Situation, in der ich regelmäßig Cast-Werte eingebe, betrifft numerische SQL-Parameter. Sie sollten jeden Eingabewert bereinigen/maskieren, den Sie in SQL-Anweisungen einfügen, oder (viel besser) parametrisierte Abfragen verwenden. Wenn Sie jedoch einen Wert wünschen, der eine Ganzzahl sein muss, ist es viel einfacher, ihn einfach umzuwandeln.

Erwägen:

function get_by_id ($id) {
   $id = (int)$id;
   $q = "SELECT * FROM table WHERE id=$id LIMIT 1";
   ........
}

wenn ich die erste Zeile weggelassen habe, $id wäre ein einfacher Vektor für die SQL-Injection. Die Besetzung stellt sicher, dass es sich um eine harmlose Ganzzahl handelt. Jeder Versuch, SQL einzufügen, führt einfach zu einer Abfrage nach id=0

15
Javier

Eine Verwendung für das Typ-Casting in PHP, die ich gefunden habe:

Ich entwickle eine Android App, die http-Anfragen an PHP Skripte auf einem Server sendet, um Daten aus einer Datenbank abzurufen. Das Skript speichert Daten in Form eines PHP -Objekts (oder eines assoziativen Arrays)) und werden als JSON-Objekt an die App zurückgegeben. Ohne Typumwandlung würde ich Folgendes erhalten:

{ "user" : { "id" : "1", "name" : "Bob" } }

Verwenden Sie jedoch PHP Typ Casting (int) auf der Benutzer-ID beim Speichern des PHP -Objekts, ich erhalte dies stattdessen an die App zurückgegeben:

{ "user" : { "id" : 1, "name" : "Bob" } }

Wenn dann das JSON-Objekt in der App analysiert wird, muss ich die ID nicht mehr in eine Ganzzahl analysieren!

Siehe, sehr nützlich.

4
Ryan

Ein Beispiel sind Objekte mit einer __toString-Methode: $str = $obj->__toString(); vs $str = (string) $obj;. In der Sekunde wird viel weniger getippt, und das zusätzliche Zeug ist die Interpunktion, deren Eingabe länger dauert. Ich denke auch, dass es besser lesbar ist, obwohl andere anderer Meinung sein können.

Ein anderes ist das Erstellen eines Einzelelement-Arrays: array($item); vs (array) $item;. Dadurch wird ein beliebiger Skalartyp (Ganzzahl, Ressource usw.) in ein Array eingefügt.
Alternativ, wenn $item ist ein Objekt, dessen Eigenschaften zu Schlüsseln für ihre Werte werden. Ich denke jedoch, dass die Objekt-> Array-Konvertierung etwas seltsam ist: Private und geschützte Eigenschaften sind Teil des Arrays und werden umbenannt. Um die PHP-Dokumentation zu zitieren : Private Variablen haben den Klassennamen vor den Variablennamen; Geschützte Variablen haben ein '*' vor dem Variablennamen.

Eine andere Verwendung ist das Konvertieren von GET/POST-Daten in geeignete Typen für eine Datenbank. MySQL kann dies selbst erledigen, aber ich denke, dass die ANSI-kompatibleren Server die Daten möglicherweise ablehnen. Der Grund, warum ich nur Datenbanken erwähne, ist, dass in den meisten anderen Fällen an den Daten irgendwann eine Operation entsprechend ihrem Typ ausgeführt wird (d. H. In int/float werden normalerweise Berechnungen usw. durchgeführt).

3
Alan Pearce

Es kann auch als schnelle und schmutzige Methode verwendet werden, um sicherzustellen, dass nicht vertrauenswürdige Daten nicht beschädigt werden, z. B. wenn ein Remote-Dienst verwendet wird, der eine Mistvalidierung aufweist und nur Zahlen akzeptieren darf.

$amount = (float) $_POST['amount'];

if( $amount > 0 ){
    $remoteService->doacalculationwithanumber( $amount );    
}

Offensichtlich ist dies fehlerhaft und wird auch vom Vergleichsoperator in der if-Anweisung implizit behandelt, ist jedoch hilfreich, um sicherzustellen, dass Sie genau wissen, was Ihr Code tut.

0
Gruffputs

Dieses Skript:

$tags = _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

läuft gut für script.php?tags[]=one, schlägt aber für script.php?tags=one fehl, da _GET['tags'] im ersten Fall ein Array zurückgibt, im zweiten jedoch nicht. Da das Skript so geschrieben ist, dass es ein Array erwartet (und Sie weniger Kontrolle über die an das Skript gesendete Abfragezeichenfolge haben), kann das Problem gelöst werden, indem das Ergebnis von _GET Entsprechend umgewandelt wird:

$tags = (array) _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}
0
beldaz