Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
275 views
in Technique[技术] by (71.8m points)

php - Odd behaviour in a switch statement

I'm writing code for a sortable table, where clicking the links in the header change the ORDER BY executed when generating a set of search results (the case where there there is no valid order by causes the query to not be run with order by and just return the results in the order the database returns. this is as designed). The code is being written within a framework provided by my employer.

To validate the ORDER BY part of the query I run the input through the following validation function.

<?php
function sortMode ($name)
{
    $mode   = '';
    switch ($name)
    {
        case 'resnum'   : $mode = 'b_resnum';            break;
        case 'state'    : $mode = 'st_id';               break;
        case 'name'     : $mode = 'lastname, firstname'; break;
        case 'phone'    : $mode = 'phone';               break;
        case 'email'    : $mode = 'email';               break;
        case 'opened'   : $mode = 'cs_created';          break;
        default         : $mode = '';                    break;
    }
    return ($mode);
}
?>

Under testing I discovered that if no parameter was provided then the sort order would be resnum. After some experimentation, I discovered that the filtering built into the framework would cause a request for an uninitialized variable such as an unset GET parameter to return integer 0. If the above code got fed a 0 integer as its input it would always follow the first path of execution available to it.

As an experiment I tried rearranging the order of the cases in the switch statement, and found whatever was at the top would be what was executed if this function was passed a 0.

The solution to the problem was using switch (strval($name)) so the particular problem is solved, but now I'm curious as to the general behaviour of PHP switch statements. Is the behaviour I witnessed the correct behaviour for PHP? Is there some fault in PHP that's causing this, or have I made an error in my code of which I'm not aware?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's because of the way php casts strings to ints. When you pass in a 0, you are asking it to do an integer comparison, so it will convert all of your case keys to integers. When php casts a string to an int, it looks for an actual number at the beginning of the string, and gobbles the number up until it hits a non-number. Since the string "resnum" has no numbers, it returns 0. See here:

php > echo (int)"100";
100
php > echo (int)"300 dogs";
300
php > echo (int)"resnum";
0
php > echo (int)"resnum 100";
0

Since all of those strings cast to 0, the first case would evaluate to true since 0 == 0.

Resources:
String conversion to numbers
Type comparison tables


Nitpick time. When you're doing simple case statements that map a string to a string, use an array. It's much clearer and actually faster:

function sortMode ($name)
{
    $modeMap = array(
        'resnum'   => 'b_resnum',
        'state'    => 'st_id',
        'name'     => 'lastname, firstname',
        'phone'    => 'phone',
        'email'    => 'email',
        'opened'   => 'cs_created'
    );

    return isset($modeMap[$name]) ? $modeMap[$name] : '';
}

If the $name is set in the map, we return the value that key is mapped to. Otherwise, we return an empty string, which takes the place of the default case.

As a bonus, you would have noticed the bug earlier if you did the above method, because it would be trying to access $modeMap[0] and would have returned your default case instead.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...