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


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.


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.


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';
}

+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);
}}    

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.


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.


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.


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;
}

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.)


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;
}


Ü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;
    }

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.


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;
    }
}

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


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;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.