PHP: Going to Zero

2 12 2014

Flickr: by djniks

Following in the tradition of its predecessor Perl, PHP has its own secret operators (see “Inchworm on a Stick“).Today let’s explore the heretofore unknown PHP operator, “->”, most remarkable for quickly reducing a numerical value to zero.  At first sight, one might mistake this symbol for PHP’s arrow operator designed to access an object’s properties and methods, until one realizes that two hyphens instead of one distinguish this arrow.  So, why have we yet to hear about this new operator? What is its name and why does the operator precedence table (see Manual) neglect to include it?


The following example should help one to discover some of the answers. The snippet is a translation of some C code found here:

<?php

 $x = 10;
 while( $x --> 0 ) // x goes to 0
 {
     printf("%d ", $x);
 }

Since the C source code executes flawlessly, will PHP’s Zend Engine allow for the unknown > operator? Or, will the symbol trip up the engine and lead to ugly error messages? Surprisingly, the lexing, parsing and execution all run smoothly, resulting in the following output:


9 8 7 6 5 4 3 2 1 0

The Deception

In truth, the > can scarcely rank as a brand-new operator, let alone a legitimate one. The space between $x and the pseudo-operator creates a misleading impression, one that suggests that the two subsequent hyphens have scant bearing on $x. In reality, they comprise a post-decrement operator which assuredly affects the variable’s value. Further complicating matters visually, the post decrement operator appears joined with the logical greater-than symbol. When the code executes, however, post-decrementing the variable and the logical comparison occur as separate actions.

Whose on First?

One question that arises, which action will occur first? If one peruses the opcodes generated by the script in the below listing, the ordered opcodes readily answer that question, showing that the opcode POST_DEC corresponding to the ‘--‘ operator appears before the logical comparison IS_SMALLER opcode. (Note, owing to the non-existence of an IS_LARGER opcode, IS_SMALLER handles logical comparison for both the ‘<‘ and ‘>’ operators).

number of ops:  9
compiled vars:  !0 = $x
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   3     0  >   ASSIGN                                                   !0, 10
   4     1  >   POST_DEC                                         ~1      !0
         2      IS_SMALLER                                       ~2      0, ~1
         3    > JMPZ                                                     ~2, ->8
   6     4  >   SEND_VAL                                                 '%25d%09'
         5      SEND_VAR                                                 !0
         6      DO_FCALL                                      2          'printf'
   7     7    > JMP                                                      ->1
         8  > > RETURN                                                   1

(See larger view).

After compiled variable (CV) !0, representing $x, takes on a value, ten initially, the CV is post-decremented and emits a temporary variable ~1 which holds the return value of !0, namely its value prior to post-decrementing it. If zero compares less than ~1 then temporary variable ~2 holds a true result which facilitates !0 passing as an argument to printf(). Since !0 was post-decremented, that value appears as the function’s output. When ~1 evaluates as zero, the comparison fails as you might expect. But !0 has been decremented to -1 and yet that result does not display. Why? At this point, execution bypasses printing of that value since it jumps to the RETURN opcode which returns 1 to indicate that the script executed successfully.

A question that still lurks, concerns the reason that the post-decrement operator executes before the greater-than operator. One might have expected that the opcodes ‘IS_SMALLER’ and ‘POST_DEC’ would appear in reverse order, because the post-decrement operator usually executes last in an expression, as follows:

<?
$a = 10;
$b = $a;
echo $a++ + $b;  // 20

Returning to the POST_DEC opcode, it must appear first since its corresponding operator ‘-‘ has greater precedence than ‘>’. What may appear as one expression are really two, evident if you encompass $x in parentheses as follows:

<?php

 $x = 10;
 while( ($x--) > 0 )     // $x evals as 10
 {
     printf("%d ", $x); // prints decremented $x
 }

Applicability

As to how one might apply this pseudo-operator, in some circumstances it may be advantageous for better performance to iterate through a collection of data starting at the top and going downward (see this article). Instead of using a for-loop with the customary initialization, test and update expressions, using > in a while loop provides simplicity although some might question the expression’s legibility.

More Secret Operators

Perhaps this pseudo-operator merits at least a name, such as go2zero. But, one might counter that it’s unwise to glorify such seemingly sloppy coding with operator status, including a name. Others may rightfully argue that this pseudo-operator has its limitations; it only works with positive numbers. If you change the value of $x to any negative number, the loop immediately fails upon comparing zero against the variable. Mercifully, another pseudo-operator which appears as ‘++<' can take a negative number to zero as this next example illustrates:

<?php

$x = -10;

while ($x ++< 0) {
    printf("%d ",$x);
}

-9 -8 -7 -6 -5 -4 -3 -2 -1 0

Of course, if you need to get to zero fast and diminish another value, you could always use the pseudo-operator ‘--‘, as follows:

<?php
$a = 10;
$b = $a;
echo $a --- $b, $a;// 0, 9

In the last line of the snippet, $a evaluates as 10 and subtracts $b. Since $a has been decremented to nine, that value is the one that displays after the resulting zero.

Lesson Learned

Reviewing only PHP source code at times may be insufficient since appearances can be deceiving. So, when in doubt one may need to dig deeper into PHP’s internal workings, or at least review its byte code as the opcodes are sometimes collectively referred.

Recommended Reading

 

This work is licensed under a Creative Commons License

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: