Der beste Weg, um einen PHP-Wechsel mit mehreren Werten pro Fall durchzuführen?

70

Wie würden Sie diese PHP-switch-Anweisung ausführen?

Beachten Sie auch, dass dies viel kleinere Versionen sind. Der 1, die ich erstellen muss, werden viel mehr Werte hinzugefügt.

Version 1:

switch ($p) { 
    case 'home': 
    case '': 
        $current_home = 'current';
    break; 

    case 'users.online': 
    case 'users.location': 
    case 'users.featured': 
    case 'users.new': 
    case 'users.browse': 
    case 'users.search': 
    case 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

Version 2:

switch ($p) { 
    case 'home': 
        $current_home = 'current';
    break; 

    case 'users.online' || 'users.location' || 'users.featured' || 'users.browse' || 'users.search' || 'users.staff': 
        $current_users = 'current';
    break;

    case 'forum': 
        $current_forum = 'current';
    break; 
} 

UPDATE - Testergebnisse

Ich habe einen Geschwindigkeitstest mit 10.000 Iterationen durchgeführt.

Time1: 0.0199389457703 // If-Anweisungen
Time2: 0.0389049446106 // switch-Anweisungen
Time3: 0.106977939606 // Arrays

JasonDavis
quelle
32
Version 2 macht nicht das, was Sie denken.
zu viel PHP
6
Version 2 funktioniert nicht, lesen Sie hier für weitere Informationen: nutt.net/2004/12/28/multiple-cases-for-switch-construct
GusDeCooL
@jasondavis Wenn Sie variable Variablen verwenden, haben Sie einen Code, der KLEIN UND EINFACH ist, so wie ich es mag =) Überprüfen Sie meine Antwort, sie ist getestet und funktioniert.
Omar

Antworten:

53

In jeder Situation, in der Sie eine unbekannte Zeichenfolge haben und herausfinden müssen, zu welcher einer Reihe anderer Zeichenfolgen sie passt, besteht die einzige Lösung, die nicht langsamer wird, wenn Sie weitere Elemente hinzufügen, darin, ein Array zu verwenden, aber alle zu haben die möglichen Zeichenfolgen als Schlüssel. So kann Ihr Schalter durch Folgendes ersetzt werden:

// used for $current_home = 'current';
$group1 = array(
        'home'  => True,
        );

// used for $current_users = 'current';
$group2 = array(
        'users.online'      => True,
        'users.location'    => True,
        'users.featured'    => True,
        'users.new'         => True,
        'users.browse'      => True,
        'users.search'      => True,
        'users.staff'       => True,
        );

// used for $current_forum = 'current';
$group3 = array(
        'forum'     => True,
        );

if(isset($group1[$p]))
    $current_home = 'current';
else if(isset($group2[$p]))
    $current_users = 'current';
else if(isset($group3[$p]))
    $current_forum = 'current';
else
    user_error("\$p is invalid", E_USER_ERROR);

Dies sieht nicht so sauber aus wie eine switch(), aber es ist die einzige schnelle Lösung, bei der keine kleine Bibliothek mit Funktionen und Klassen geschrieben wird, um Ordnung zu schaffen. Es ist immer noch sehr einfach, Elemente zu den Arrays hinzuzufügen.

zu viel php
quelle
1
Um technisch korrekt zu sein, wird dies langsamer, wenn Sie mehr Elemente hinzufügen. Es wird nur viel langsamer langsamer. Hash-Tabellen sind unglaublich schnell, aber nicht magisch :-)
Moodboom
26

Version 2 funktioniert nicht !!

case 'users.online' || 'users.location' || ...

ist genau das gleiche wie:

case True:

und das casewird für jeden Wert von gewählt $p, es $psei denn, es ist die leere Zeichenfolge.

||Hat keine besondere Bedeutung in einer caseAnweisung, Sie vergleichen nicht $pmit jeder dieser Zeichenfolgen, Sie überprüfen nur, ob dies nicht der Fall ist False.

zu viel php
quelle
OK, würden Sie denken, dass die Verwendung eines Schalters oder einer if-Anweisung schneller ist als das Erstellen mehrerer Arrays und das mehrmalige Überprüfen, ob sich ein Wert in einem Array befindet?
JasonDavis
Ich habe noch nie etwas gehört oder gelesen, das mich glauben lässt, ein Schalter () wäre schneller. Eine Route wird immer noch eine ganze Reihe von Zeichenfolgenvergleichen durchführen.
zu viel PHP
Hier ist etwas, das zeigt, dass ein Array möglicherweise langsamer ist stackoverflow.com/questions/324665/…
JasonDavis
8

Fügen Sie diese vielen Werte in ein Array ein und fragen Sie das Array ab, da der Switch-Fall die zugrunde liegende Semantik dessen zu verbergen scheint, was Sie erreichen möchten, wenn eine Zeichenfolgenvariable als Bedingung verwendet wird, was das Lesen und Verstehen erschwert, z ::

$current_home = null;
$current_users = null;
$current_forum = null;

$lotsOfStrings = array('users.online', 'users.location', 'users.featured', 'users.new');

if(empty($p)) {
    $current_home = 'current';
}

if(in_array($p,$lotsOfStrings)) {
    $current_users = 'current';
}

if(0 === strcmp('forum',$p)) {
    $current_forum = 'current';
}
karim79
quelle
+1 Als ich die Frage zum ersten Mal las, kam mir diese Lösung zuerst in den Sinn. Wenn die Anzahl der Fälle zunimmt, müssen Sie dem Array lediglich Werte hinzufügen und sich auf das in_array verlassen, um seine Aufgabe zu erledigen.
Randell
In meinem Fall hätte ich auf diese Weise viele verschiedene Arrays, also würde ich das in_array gegen mehrere Arrays ausführen. Glauben Sie, dass es auf eine Weise einen Leistungsgewinn gegenüber einer anderen gibt?
JasonDavis
Ich habe nicht versucht, es zu vergleichen, es ist einfacher zu lesen, insbesondere wenn Sie Konstanten verwenden. Wie viele verschiedene Arrays (und Größen) erwarten Sie?
Randell
Ich denke nicht, dass es einen wahrnehmbaren Leistungsunterschied geben wird. Selbst wenn dies der Fall wäre, würde ich mich wahrscheinlich immer noch an das oben Gesagte halten, da es für mich in Bezug auf Lesbarkeit und Wartbarkeit nur sinnvoller ist.
Karim79
@ Randell Dies wird für eine Menüauswahl auf einer Website mit hohem Datenverkehr verwendet, sodass nur etwa 8 Arrays vorhanden sind und einige von ihnen jeweils bis zu 15 Elemente enthalten können. Ich weiß, dass es nicht GROSS ist, aber es wird zusätzliche Arbeit geleistet Es wird viel Verkehr geben und dies wird bei jedem einzelnen Seitenaufruf geschehen. Deshalb
frage
6

Aus Gründen der Vollständigkeit, werde ich darauf hinweisen, dass die gebrochene „Version 2“ Logik kann das Arbeiten mit einer switch - Anweisung ersetzt werden, und auch die Verwendung von Arrays für Geschwindigkeit und Klarheit, wie so machen:

// verwendet für $ current_home = 'current';
$ home_group = array (
    'home' => Richtig,
);

// verwendet für $ current_users = 'current';
$ user_group = array (
    'users.online' => True,
    'users.location' => True,
    'users.featured' => True,
    'users.new' => True,
    'users.browse' => True,
    'users.search' => True,
    'users.staff' => True,
);

// verwendet für $ current_forum = 'current';
$ forum_group = array (
    'forum' => Richtig,
);

switch (true) {
    case isset ($ home_group [$ p]):
        $ current_home = 'current';
        Unterbrechung;
    case isset ($ user_group [$ p]):
        $ current_users = 'current';
        Unterbrechung;
    case isset ($ forum_group [$ p]):
        $ current_forum = 'current';
        Unterbrechung;
    Standard:
        user_error ("\ $ p ist ungültig", E_USER_ERROR);
}}    
Peter
quelle
4

Wenn irgendjemand Ihren Code jemals pflegen würde, würde er Version 2 mit ziemlicher Sicherheit doppelt übernehmen - das ist extrem unüblich.

Ich würde bei Version 1 bleiben. Ich bin von der Schule, obwohl diese Fallaussagen ohne eigenen Anweisungsblock einen expliziten // fall throughKommentar neben sich haben sollten, um anzuzeigen, dass es tatsächlich Ihre Absicht ist, durchzufallen, wodurch jegliche Unklarheit darüber beseitigt wird, ob Sie wollten die Fälle anders behandeln und vergessen oder so.

Mark Rushakoff
quelle
4

Einige andere Ideen, die noch nicht erwähnt wurden:

switch(true){ 
  case in_array($p, array('home', '')): 
    $current_home = 'current'; break;

  case preg_match('/^users\.(online|location|featured|new|browse|search|staff)$/', $p):
    $current_users = 'current'; break;

  case 'forum' == $p:
    $current_forum = 'current'; break; 
}

Jemand wird sich wahrscheinlich über Lesbarkeitsprobleme mit # 2 beschweren, aber ich hätte kein Problem damit, solchen Code zu erben.

pguardiario
quelle
Komisch, ein Freund von mir hat mir gerade einen sehr ähnlichen Code geschickt, der besagt, dass er funktioniert, und ich bin sofort zu Stack Overflow gekommen, um zu sehen, ob jemand anderes dies als Lösung angesehen hat. Ich finde es ziemlich cool
Samrap
Ordentliche Umsetzung.
Hayatu Mohammed Abubakar
3

Version 1 ist sicherlich augenschonender, klarer in Bezug auf Ihre Absichten und einfacher, Fallbedingungen hinzuzufügen.

Ich habe die zweite Version noch nie ausprobiert. In vielen Sprachen würde dies nicht einmal kompiliert werden, da die einzelnen Fallbezeichnungen zu einem konstanten Ausdruck ausgewertet werden müssen.

Robert Cartaino
quelle
2

Heutzutage können Sie tun ...

switch ([$group1, $group2]){
    case ["users", "location"]:
    case ["users", "online"]:
        Ju_le_do_the_thing();
        break;
    case ["forum", $group2]:
        Foo_the_bar();
        break;
}
Liljoshu
quelle
1

Ich bevorzuge definitiv Version 1. Version 2 erfordert möglicherweise weniger Codezeilen, aber es wird extrem schwer zu lesen sein, wenn Sie viele Werte darin haben, wie Sie es vorhersagen.

(Ehrlich gesagt wusste ich bis jetzt nicht einmal, dass Version 2 legal ist. Ich habe es noch nie so gesehen.)

Josh Leitzel
quelle
1

Keine Version 2 funktioniert tatsächlich nicht, aber wenn Sie diese Art von Ansatz wünschen, können Sie Folgendes tun (wahrscheinlich nicht die schnellste, aber wohl intuitivere):

switch (true) {
case ($var === 'something' || $var === 'something else'):
// do some stuff
break;
}

Tomfumb
quelle
Überhaupt nicht intuitiv. Dies könnte durch eine einfache ifAussage ersetzt werden.
Kbanman
1

könnte sein

        switch ($variable) {
        case 0:
            exit;
            break;
        case (1 || 3 || 4 || 5 || 6):
            die(var_dump('expression'));
        default:
            die(var_dump('default'));
            # code...
            break;
    }
Timenty Ogurtsov
quelle
1
Besser, wenn Sie Ihre Antwort erklären und Ihren Code neu formatieren
Gagantous
0

Ich denke, Version 1 ist der richtige Weg. Es ist viel einfacher zu lesen und zu verstehen.

Josh Curren
quelle
0
if( in_array( $test, $array1 ) )
{
    // do this
}
else if( stristr( $test, 'commonpart' ) )
{
    // do this
}
else
{
    switch( $test )
    {
        case 1:
            // do this
            break;
        case 2:
            // do this
            break;
        default:
            // do this
            break;
    }
}
Ein alter Mann
quelle
0

Ein Wechsel in Kombination mit variablen Variablen bietet Ihnen mehr Flexibilität:

<?php
$p = 'home'; //For testing

$p = ( strpos($p, 'users') !== false? 'users': $p);
switch ($p) { 
    default:
        $varContainer = 'current_' . $p; //Stores the variable [$current_"xyORz"] into $varContainer
        ${$varContainer} = 'current'; //Sets the VALUE of [$current_"xyORz"] to 'current'
    break;

}
//For testing
echo $current_home;
?>

Um mehr zu erfahren, überprüfen Sie die Variablenvariablen und die Beispiele, die ich im PHP-Handbuch eingereicht habe:
Beispiel 1 : http://www.php.net/manual/en/language.variables.variable.php#105293
Beispiel 2 : http: // www .php.net / manual / de / language.variables.variable.php # 105282

PS: Dieser Beispielcode ist KLEIN UND EINFACH , genau so, wie ich es mag. Es ist getestet und funktioniert auch

Omar
quelle
1
OP fragt, wie im Allgemeinen mehrere caseBedingungen am effizientesten kombiniert werden können.
Jprofitt
0

Sie suchen einfach nach allgemeinen Mustern in Zeichenfolgen. Ich hätte gedacht, ein regulärer Ausdruck wäre eine effizientere Möglichkeit, dies zu tun, da PHP dies mit preg_match implementiert, so wenig Code zum Schreiben und wahrscheinlich massiv schneller. Zum Beispiel:

case preg_match('/^users./'):
// do something here
break;
user5688936
quelle