How to use a PHP switch statement to check if a st

2019-04-03 18:16发布

问题:

I'm using a PHP switch to include certain files based on the incoming keywords passed in a parameter of the page's URL.

The URL, for example, could be: ...page.php?kw=citroen%20berlingo%20keywords

Inside the page, I'd like to use something like this:

<?
    switch($_GET['kw']){

        case "berlingo":     
            include 'berlingo.php'
            break;
        case "c4":
            include 'c4.php';
            break;

    } 
?>

What I want to do in the first case is include the berlingo.php file if the keyword parameter contains berlingo, but it doesn't have to be exactly that keyword alone.

For example, I want to include the berlingo.php file if the keyword is berlingo, but also if it's citroen berlingo.

How can I evaluate if a given string contains a value using a PHP case select (switch statement)?

Thanks.

回答1:

Based on this question and this answer, the solutions I've come up with (while still using a case select) are below.

You can use either stristr() or strstr(). The reason I chose to use stristr() in this case is simply because it's case-insensitive, and thus, is more robust.

Example:

$linkKW = $_GET['kw'];

switch (true){
   case stristr($linkKW,'berlingo'):
      include 'berlingo.php';
      break;
   case stristr($linkKW,'c4'):
      include 'c4.php';
      break;
}

You could also use stripos() or strpos() if you'd like (thanks, Fractaliste), though I personally find this more difficult to read. Same deal as the other method above; I went the case-insensitive route.

Example:

$linkKW = $_GET['kw'];

switch (true){
   case stripos($linkKW,'berlingo') !== false:
      include 'berlingo.php';
      break;
   case stripos($linkKW,'c4') !== false:
      include 'c4.php';
      break;
}


回答2:

Since in a switch statement only a simple equality testing will be performed it won't help you much here. You need to run the string through a string matching function, best suited of which is strpos. The straight forward answer is:

if (strpos($_GET['kw'], 'berlingo') !== false) {
    include 'berlingo.php';
} else if (strpos($_GET['kw'], 'c4') !== false) {
    include 'c4.php';
} … and so on …

The more elegant solution would be something like this:

$map = array('berlingo' => 'berlingo.php', 'c4' => 'c4.php', …);
foreach ($map as $keyword => $file) {
    if (strpos($_GET['kw'], $keyword) !== false) {
        include $file;
        break;
    }
}

Or, if the correspondence between the keyword and the file is always 1:1:

$keywords = array('berlingo', 'c4', …);
foreach ($keywords as $keyword) {
    if (strpos($_GET['kw'], $keyword) !== false) {
        include "$keyword.php";
        break;
    }
}


回答3:

You can use strpos function as:

if(strpos($_GET['kw'],'berlingo') !== false) {
 include 'berlingo.php';
}
if(strpos($_GET['kw'],'c4') !== false) {
 include 'c4.php';
}


回答4:

$keywords = array('berlingo', 'c4');
foreach($keywords as $keyword)
  if(strpos($_GET['kw'], $keyword) !== FALSE)
    include("$keyword.php");

I wouldn't recommend including php files based on user input though.



回答5:

You can also use regular expression in switch -> case:

<?php

    $kw = filter_input(INPUT_GET, "kw");

    switch($kw){

        case (preg_match('/*berlingo*/', $kw) ? true : false):     
            include 'berlingo.php';
            break;

        case "c4":
            include 'c4.php';
            break;

    } 
?>


回答6:

strpos() is one for checking if a string contains another string.

There are other functions for checking similarity of strings, etc.

A switch won't do, though, since it compares static expressions against a single value. You'll have to use ifs.



回答7:

I know this is WAY after the fact, but just as an aside, one can always avoid the loop altogether if expecting a 1:1 relationship.

Something along the lines of:

$map = array('berlingo' => 'berlingo.php', 'c4' => 'c4.php', …);

if( !isset( $map[$_GET['kw']] ))
    throw new Exception("Blah!!");

include $map[$_GET['kw']];

...just sharing as an FYI for newbies.



回答8:

In my opinion, it's a code smell if you're including scripts via GET variables, but you can do this elegantly using a value class with methods whose logic return the value object itself if true.

The idea is to keep in mind that a switch statement will execute any code where $switch == $case (a loose match). So just create methods which either return $this, or nothing at all.

Example:

class Haystack {
    public $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public function contains($needle):
    {
        if (strpos($this->value, $needle) !== false)
            return $this;
    }
}

$kw = new Haystack($_GET['kw']);

switch ($kw) {
    case $kw->contains('berlingo'):
        require_once 'berlingo.php';
    case $kw->contains('c4'):
        require_once 'c4.php';
}

You can, of course, generously garnish this code with typehints. If you do, and are not using a version of PHP which supports nullable return types (ie a method signature of public function contains(string $substring): ?Haystack) then your class would have to elaborate to reflect that.

Example:

final class Haystack {
    private $value;
    private $isMain;

    public function __construct(string $value, bool $isMain = true)
    {
        $this->value = $value;
        $this->isMain = $isMain;
    }

    final public function contains($needle): Haystack
    {
        if (strpos($this->value, $needle) !== false)
            return $this;
        return new Haystack($needle, false);
    }
}

This way, if your explicit matching logic fails inside the method, if for some reason new Haystack($_GET['kw']) == new Haystack($needle); is true, the non-matching property "$isMain" will ensure they are not evaluated as equal.

Again, I would re-examine why you'd want to do this in the first place for this particular situation; traditionally, Composer is a dependency management tool which would be used to include various scripts you need via a PSR autoload standard. That in combination with a Router library would probably be the most useful to address your actual needs.