Let Me Count The Ways …

1 11 2014

Flickr: by Dom Dada

Elizabeth Barrett Browning pondered affairs of the heart when she penned her famous love poem, a fragment of which entitles this piece as an acknowledgment of PHP’s characteristic TIMTOWTDI (“there is more than one way to do it”) approach, particularly prevalent in displaying data.

One of the earliest ways to do output involved PHP utilizing an echo command written in C for the express purpose of displaying the results of functions and variables in PHP/FI (see museum.php.net: PHP/FI 1.99s: echo.c, demo_echo.html and doc.html).  The command seems to be a cross between the echo command of bash and the printf function in the C programming language.  Later for PHP3, echo became a construct, i.e. it became built into the PHP language itself and it lost its formatting ability in the process.

To gain a deeper understanding of echo and its ways, necessitates moving beyond scrutinizing PHP’s behavior to inspecting opcodes as well as taking a peek at the internal C-source code. This type of investigation can potentially lead to some amazing discoveries.

Consider the following snippet:

list($action,$what) = array("Raining ","Cats 'n Dogs");

echo $action . $what,"\n";
echo $action, $what,"\n";

echo $action;
echo $what;
echo "\n";

echo "$action$what\n";
echo "{$action}{$what}\n";
echo "${'action'}${'what'}\n";
echo "${action}${what}\n";

The preceding echo statements repetitively display “Raining Cats ‘n Dogs”, even though the internal C-source code may differ, depending on whether the solution involves concatenation, interpolation or simply multiple arguments.

The first echo statement, nearly identical with the second, uses a dot while the the latter a comma. These seemingly inconsequential punctuation differences impact the kinds of opcodes that these statements generate.

The following listing shows the opcodes corresponding to the first statement:

compiled vars:  !0 = $action, !1 = $what

      CONCAT                                 ~5      !0, !1
      CONCAT                                 ~6      ~5, '%0A'
      ECHO                                           ~6

You will note that the opcode information specifies two compiled variables !0 and !1 which respectively represent $action and $what. Compiled variables are an optimization feature that the Zend Engine2 introduced starting with PHP5.1. When the script executes, the two variables are concatenated and that result is returned in temporary variable ~5. Next, the newline character represented by ‘%0A’, a url-style hex code, is appended to the temporary variable. The resulting new value will be held by a different temporary variable, ~6, whose contents echo happily displays.

The second statement uses the ‘,’ which functions here as a separator of the arguments to echo. While the statement in PHP only contains one echo, that line of code will generate three ECHO opcodes, as follows:

      ECHO                                                !0
      ECHO                                                !1
      ECHO                                                '%0A'

So, despite all appearances, internally the second statement and the next three generate the same three ECHO opcodes. The ability of echo in the second statement to handle multiple arguments is not inherent to this construct but rather a quality bestowed by this parser rule, which states that echo may take one argument or a comma-separated list of expressions.

The last four statements depict different syntax for variable interpolation, all of which yield the same opcodes, as follows:

        ADD_VAR                                ~7      !0
        ADD_VAR                                ~7      ~7, !1
        ADD_CHAR                               ~7      ~7, 10
        ECHO                                           ~7

The first ADD_VAR causes !0 ($action) to be added to the string buffer and produces temporary variable ~7. Like CONCAT, this opcode gives the impression that strings are being added together while internally the C function memcpy mimics addition by copying a string in one memory area to another also storing string data. Whether the operation concerns concatenation or, as in this case, interpolation, the copied string follows immediately after the original string stored at the destination source.

The second ADD_VAR appends !1 ($what) to ~7. The ADD_CHAR causes the newline character shown with its ASCII value 10 to finish the string value ~7 contains. The last opcode shows the variable as an operand for ECHO to display its contents.

Given these various ways of displaying data, which is the fastest? Probably the single or three-some echo statements that merely output data, with the help of the internal zend_print_variable(); see http://lxr.php.net/xref/PHP_5_6/Zend/zend_vm_def.h#969. After that the question becomes a choice of choosing between concatenation or interpolation. According to Nikita Popov, the more variables for interpolation, the more efficient that interpolation becomes because the code repeatedly reuses the same temporary variable, as seen in the preceding example.

Recommended Related-Reading

This work is licensed under a Creative Commons License



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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: