• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 递增/递减运算符

    PHP 支持 C 风格的前/后递增与递减运算符。

    Note:递增/递减运算符不影响布尔值。递减NULL值也没有效果,但是递增NULL的结果是1

    递增/递减运算符
    例子名称效果
    ++$a前加$a的值加一,然后返回$a
    $a++后加返回$a,然后将$a的值加一。
    --$a前减$a的值减一,然后返回$a
    $a--后减返回$a,然后将$a的值减一。

    一个简单的示例脚本:

    <?php
    echo "<h3>Postincrement</h3>";
    $a = 5;
    echo "Should be 5: " . $a++ . "<br />\n";
    echo "Should be 6: " . $a . "<br />\n";
    echo "<h3>Preincrement</h3>";
    $a = 5;
    echo "Should be 6: " . ++$a . "<br />\n";
    echo "Should be 6: " . $a . "<br />\n";
    echo "<h3>Postdecrement</h3>";
    $a = 5;
    echo "Should be 5: " . $a-- . "<br />\n";
    echo "Should be 4: " . $a . "<br />\n";
    echo "<h3>Predecrement</h3>";
    $a = 5;
    echo "Should be 4: " . --$a . "<br />\n";
    echo "Should be 4: " . $a . "<br />\n";
    ?>
    

    在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中$a ='Z';$a++;将把$a变成'AA',而在 C 中,a ='Z'; a++;将把a变成'[''Z'的 ASCII 值是 90,'['的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。

    Example #1 涉及字符变量的算数运算

    <?php
    echo '== Alphabets ==' . PHP_EOL;
    $s = 'W';
    for ($n=0; $n<6; $n++) {
        echo ++$s . PHP_EOL;
    }
    // Digit characters behave differently
    echo '== Digits ==' . PHP_EOL;
    $d = 'A8';
    for ($n=0; $n<6; $n++) {
        echo ++$d . PHP_EOL;
    }
    $d = 'A08';
    for ($n=0; $n<6; $n++) {
        echo ++$d . PHP_EOL;
    }
    ?>
    

    以上例程会输出:

    == Characters ==
    X
    Y
    Z
    AA
    AB
    AC
    == Digits ==
    A9
    B0
    B1
    B2
    B3
    B4
    A09
    A10
    A11
    A12
    A13
    A14
    

    递增或递减布尔值没有效果。

    Note that 
    $a="9D9"; var_dump(++$a);  => string(3) "9E0"
    but counting onwards from there 
    $a="9E0"; var_dump(++$a);  => float(10)
    this is due to "9E0" being interpreted as a string representation of the float constant 9E0 (or 9e0), and thus evalutes to 9 * 10^0 = 9 (in a float context)
    Please note the difference between post-incrementing in a for-loop and recursive function calls (don't use it in the latter!).
    <?php
    $increment = $preIncrement = $postIncrement = 1;
    echo $increment.' - '.$preIncrement.' - '.$postIncrement;
    echo '<br>';
    echo ($increment+1).' - '.(++$preIncrement).' - '.($postIncrement++);
    echo '<br>';
    echo ($increment+1).' - '.(++$preIncrement).' - '.($postIncrement++);
    echo '<br>';
    echo ($increment+1).' - '.(++$preIncrement).' - '.($postIncrement++);
    ?>
    Outputs:
    1 - 1 - 1
    2 - 2 - 1
    2 - 3 - 2
    2 - 4 - 3
    The for-loop:
    <?php
    for($i=0; $i<4; $i++)
    {
      echo $i.'<br>';
    }
    ?>
    Outputs:
    0
    1
    2
    3
    And the 'headache' mistake, post-increment as parameter of a recursive call:
    <?php
    testFunctionNesting(3, 1, 1, 1);
    function testFunctionNesting($max, $increment, $preIncrement, $postIncrement)
    {  
      echo $increment.' - '.$preIncrement.' - '.$postIncrement;
      echo '<br>';
      
      if($increment>=$max)
      {
        $inc = $increment;
        $pre = $preIncrement;
        $post = $postIncrement;
        return;
      }
        
      
      testFunctionNesting($max, ($increment+1), (++$preIncrement), ($postIncrement++));
    }
    ?>
    Output shows that the postIncremented value is never really available as incremented value:
    1 - 1 - 1
    2 - 2 - 1
    3 - 3 - 1
    When using the ++ operator by itself on a variable, ++$var is faster than $var++ and uses slightly less memory (in my experiments). It would seem like this could be optimized in the language during runtime (if $var++ is the only thing in the whole statement, it could be treated as ++$var).
    I conducted many tests (I believe to be fair), and here's one of the results:
    $i++ took 8.47515535355 seconds and 2360 bytes
    ++$i took 7.80081486702 seconds and 2160 bytes
    Here's my code. If anyone sees a bias in it, tell me. I conducted it many times, each time going through a loop one million iterations and doing each test 10 - 15 times (10 - 15 million uses of the ++ operator).
    <?php
    ini_set( 'MAX_EXEC_TIME', 120 );
    ob_start( );
    $num_tests = 10;
    $startFirst = $startSecond = $endFirst = $endSecond = $startFirstMemory = $endFirstMemory = $startSecondMemory = $endSecondMemory = $someVal = 0;
    $times = array( '$i++' => array( 'time' => 0, 'memory' => 0 ), '++$i' => array( 'total' => 0, 'memory' => 0 ) );
    for( $j = 0; $j < $num_tests; ++$j )
    {
        for( $i = 0, $startFirstMemory = memory_get_usage( ), $startFirst = microtime( true ); $i < 10000000; $i++ ){ $someval = 2; }
        $endFirstMemory = memory_get_usage( );
        $endFirst = microtime( true );
        for( $i = 0, $startSecondMemory = memory_get_usage( ), $startSecond = microtime( true ); $i < 10000000; ++$i ){ $someval = 2; }
        $endSecondMemory = memory_get_usage( );
        $endSecond = microtime( true );
        $times[ '$i++' ][ $j ] = array( 'startTime' => $startFirst, 'endTime' => $endFirst, 'startMemory' => $startFirstMemory, 'endMemory' => $endFirstMemory );
        $times[ '++$i' ][ $j ] = array( 'startTime' => $startSecond, 'endTime' => $endSecond, 'startMemory' => $startSecondMemory, 'endMemory' => $endSecondMemory );
    }
    for( $i = 0; $i < $num_tests; ++$i )
    {
        $times[ '$i++' ][ 'time' ] += ( $times[ '$i++' ][ $i ][ 'endTime' ] - $times[ '$i++' ][ $i ][ 'startTime' ] );
        $times[ '++$i' ][ 'time' ] += ( $times[ '++$i' ][ $i ][ 'endTime' ] - $times[ '++$i' ][ $i ][ 'startTime' ] );
        $times[ '$i++' ][ 'memory' ] += ( $times[ '$i++' ][ $i ][ 'endMemory' ] - $times[ '$i++' ][ $i ][ 'startMemory' ] );
        $times[ '++$i' ][ 'memory' ] += ( $times[ '++$i' ][ $i ][ 'endMemory' ] - $times[ '++$i' ][ $i ][ 'startMemory' ] );
    }
    echo 'There were ' . $num_tests . ' tests conducted, here\'s the totals<br /><br />
    $i++ took ' . $times[ '$i++' ][ 'time' ] . ' seconds and ' . $times[ '$i++' ][ 'memory' ] . ' bytes<br />
    ++$i took ' . $times[ '++$i' ][ 'time' ] . ' seconds and ' . $times[ '++$i' ][ 'memory' ] . ' bytes';
    ob_end_flush( );
    ?>
    Try it yourself, ;)
    Note that the ++ and -- don't convert a boolean to an int. The following code will loop forever.
    function a($start_index) {
    for($i = $start_index; $i < 10; $i++) echo "\$i = $i\n";
    }
    a(false);
    This behavior is, of course, very different from that in C. Had me pulling out my hair for a while.
    Rule for Increment and decrement:
    At some moment we could be confused with increment and decrement in various cases. To avoid such cases, let us follow certain logical rule behind to get successful results with out mess.
    <?php
          $n = 3;
          echo $n-- + --$n; 
          echo "<br/>";
          echo $n;
    ?>
    1. Postfix form of ++,-- operator follows the rule [ use-then-change ],
    2. Prefix form (++x,--x) follows the rule [ change-then-use ].
    Solution based on the rule:
    Step 1: 
    use then change  $n-- use is 3 and change is 2
    Step 2. 
    change then use  --$n change is 2 and use is 1
    Step 3.
    use + use = (3 + 1) = 4
    Courtesy : stackoverflow : Sunil Dhillon : 4686665
    Regarding character incrementing and PHP following Perl's convention with character operations.
    Actually i found that there is a difference, and incrementing and decrementing unfortunately does not yield the reverse, expected results.
    For example, the following piece of code:
    <?php
    echo '== Alphabets ==' . PHP_EOL;
    $s = 'W';
    for ($n=0; $n<10; $n++) {
      echo ++$s . ' ';
    }
    echo PHP_EOL;
    for ($n=10; $n>0; $n--) {
      echo (--$s) . ' ';
    }
    ?>
    Will output:
    == Alphabets ==
    X Y Z AA AB AC AD AE AF AG 
    AG AG AG AG AG AG AG AG AG AG 
    Please note that the decrement operator has no effect on the character or string.
    On the other hand, in Perl, the similar script:
    #!/usr/bin/perl
    my $s = 'W';
    foreach (1 .. 10) {
    print ++$s . " ";
    } 
    print "\n";
    foreach (1 .. 10) {
    print --$s . " ";
    }
    Will output:
    X Y Z AA AB AC AD AE AF AG 
    -1 -2 -3 -4 -5 -6 -7 -8 -9 -10
    I ran some tests (on PHP 5.3.3) of my own and was surprised to find $i += 1 to be the fastest method of incrementing. Here are the methods fastest to slowest:
    $i += 1;
    ++$i;
    $i++;
    $i = $i + 1;
    (related to what "Are Pedersen" wrote)
    With arrays it can lead to much confusion if your index variable is altered on the right side of the = sign, either with ++|-- or even when passed to a function by reference..
    Consider these (PHP 5):
    <?php
    $A[$a] = ++$a; // [1]=1
    $B[++$b] = ++$b; // [1]=2
    $C[$c+=0] = ++$c; // [0]=1
    ?>
    In 'A' you have to be aware that PHP evaluates $A[$a] last.
    Yet in 'B' and 'C' PHP evaluates the index and saves it in a temporary variable.
    You can always force PHP to evaluate a variable without explicitly storing it as a named variable first, with a simple "+=0" like in example 'C'.
    Compared to 'A', 'C' gives the more logically expected result, when we expect evaluation occurs left to right.
    PHP does evaluate left to right BUT it will attempt to cut down on temporary variables, which can lead to confusing results.
    So just be aware and use either behavior to your advantage for the desired functionality.
    Other samples :
    $l="A";   $l++; -> $l="B"
    $l="A0";   $l++; -> $l="A1"
    $l="A9";   $l++; -> $l="B0"
    $l="Z99";  $l++; -> $l="AA00"
    $l="5Z9";  $l++; -> $l="6A0"
    $l="9Z9";  $l++; -> $l="10A0"
    $l="9z9";  $l++; -> $l="10a0"
    $l="J85410"; $l++; -> $l="J85411"
    $l="J99999"; $l++; -> $l="K00000"
    $l="K00000"; $l++; -> $l="K00001"
    Rule Incrementing or decrementing booleans has no effect.
    It has an effort on Incrementing or decrementing booleans.
    Please look over the code.
    $var = true;
    echo ++$var;  //Results 1
    Similarly 
    $var = true;
    echo ++$var;  //Results 1
    $var = (int)false;
    echo ++$var;  //Results 1
    $var = (int)false;
    echo $var++;  //Results 0;  
    Note : Tested on PHP Version 5.5.32
    BEWARE:
    If incrementing an uninitialized variable you will not get an E_NOTICE error. This may caused you to not find issue's like the visibility of a property.
    <?php
    class a {
      private $foo = 1;
    }
    class b extends a {
      public function inc() {
        echo ++$this->foo;
      }
    }
    $b = new b;
    $b->inc();
    ?>
    Will output 1 and not 2 (if $foo was accessible).
    Also no notices are given.
    Самое простое описание работы инкремента, которое я встречал и будет удобно для понимания новичку:
    Постинкремент возвращает значение до увеличения/уменьшения на 1
    Преинкремент возвращает значение увеличенное/уменьшенное на 1
    $b = 6;
    $a = $b++; // $a = 6, $b = 7
    $b = 6;
    $a = $b--; // $a=6, $b = 5
    $b = 6;
    $a = ++$b; // $a = 7, $b = 7
    $b = 6;
    $a = --$b; // $a = 5, $b = 5
    If you have a trailing zero and use the increment, the trailing zero will not remain. Was at least unexpected for me at first, although it's logical if you think about it.
    <?php 
    $start = '01';
    $start++;
    print $start; //Outputs '2' not '02'
    ?>
    

    上篇:执行运算符

    下篇:逻辑运算符