The Power behind the Throne

21 09 2015

flickr: from British library

 

While looking forward to the upcoming official release of the latest incarnation of PHP, namely PHP7 (slated for November 12th), spending a moment or two reviewing such basics as the expression statement should enhance one’s appreciation for PHP and how this powerful feature contributes to its feasibility, permitting it to reign more than two decades.

The Expressive Expression Statement

The expression statement derives from imperative programming, a style that arose according to this Wikipedia article because the hardware itself was built to execute code containing statements. An expression, i.e. code that may be reduced to a value, followed by a semicolon is an expression statement. The logic-defying characteristic of the expression statement is that the important part is hardly the result which gets promptly discarded; the side-effect is what matters. Here’s a trivial example:

print "PHP";  // PHP

The side-effect of output appearing ranks far more than the print construct returning a value of one, a value that the script easily ignores.

Expression statements play a pivotal role in PHP, as core contributor Andrea Faulds explains that without them:

… function calls wouldn’t work, nor would assignment, both of which are expression statements.

PHP Internals List
Nov. 20, 2014

Indeed, but how can one possibly reconcile that bit of wisdom with the following apparent foolishness:

<?php

2 < 3;   
1;   

By allowing such code to run, PHP makes it possible for the following code to execute, too:

<?php

function showPlusOne( $a, $b ) {
    
    echo $a + $b + 1,"\n";
    return true;
}

showPlusOne( 7, 8 );                  
print 20 + showPlusOne( 7, 8 );   

See live code.

The expression statements in the last two lines evaluate identically with those of the preceding snippet.

Making a Statement with None

You may encounter a variant of an expression statement, known as the empty or null statement. PHP like its forebear C supports a null statement, i.e. an expression statement without an expression, as follows:

<?php

;

See live code and zend_languge_parser.y

The script superficially appears silly when all it does is merely return true, as its solitary opcode indicates:

number of ops:  1
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   3     0  E > > RETURN                                                   1

Upon closer inspection, the opcode does more than return a value. The opcode’s compactness conceals the fact that a handler calls a helper function to do housekeeping chores for the shortest script possible.

Still, one may wonder whether the empty statement might accomplish anything more useful. Consider a for-loop like the following which seeks to initialize all the elements of an array with a default value of zero:

<?php

$line = array();
for ( $i = 0, $max = 10; $i < $max; $line[$i++] = 0 )
;
var_dump($line);

See live code.

If one were to omit the null statement, then the outcome goes off the rails with the generation of ten arrays, each composed of the number of elements corresponding to each iteration of the loop. The code must employ the null statement owing to PHP’s C legacy. According to the msdn online reference for C, the for-loop requires at least one statement in its body, even a null statement satisfies that requirement. A perusal of zend_language_parser.y confirms that PHP adheres to this rule, too.

Parenthetically-speaking of course there is an easier way to establish an array with a fixed number of elements, all sharing the same default value. You could apply array_fill(), as follows:

<?php

$line = array_fill(0,10,0);
var_dump($line);

See live code.

Or, you can use the same code as in the example, but change line one to use the SplFixedArray class, as follows:

<?php

$line = new SplFixedArray(10);
for ( $i = 0, $max = 10; $i < $max; $line[$i++] = 0 )
;
var_dump($line);

See live code.

Interestingly, the old-style for-loop syntax obviates the need for any kind of body statement, as follows:

<?php
$line = array();
for ($a=0, $max=10; $a < $max; $line[$a++] = 0):

endfor;
var_dump($line);

See live code.

Nature of the Beast

One might suppose that an expression statement containing an undefined variable would behave just like a null statement. The following example should shed some light:

<?php

$myundef;       // undefined variable
;               // null statement

See live code.

Inspecting the diagram below proves revealing:

number of ops:  1
compiled vars:  !0 = $myundef
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   4     0  E > > RETURN                                                   1

The first line produces a compiled variable (CV). I understand from Nikita Popov that internally that the CV is a NULL pointer in this case. The NULL pointer “… points definitively nowhere; it is not the address of any object or function..” (see http://c-faq.com/null/null1.html In contrast, the null statement has a negligible impact. So, the empirical evidence suggests that the statements differ from one another.

Note, neither expression statement is equivalent to ‘\0’, i.e. a null character (a character incidentally distinct from chr(0), a veritable empty string — strings in PHP do not require a null terminating character as in C). Both expression statements, being valueless, should equate with the NULL constant in PHP, a constant which stands out in stark contrast to other types since it’s the only type that lacks a value. We can test this hypothesis, as follows:

<?php

@$myundef;
null;
;

See live code.

Note the appearance of the @ error suppressor which enables the code to run without Facebook’s HHVM emitting an error notice; PHP only would require it if the code were to actually do something with the undefined variable. The result is of course uniformly nothing or is it? Take a look at the opcode diagram below:

number of ops:  5
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   3     0  E >   BEGIN_SILENCE                                    ~0      
         1        FETCH_R                      local               $1      'myundef'
         2        END_SILENCE                                              ~0
         3        FREE                                                     $1
   5     4      > RETURN                                                   1

Using the @ error suppressor actually suppressed more than the E_NOTICE; it inhibited the CV associated with $myundef from forming. Internal code may work without a CV but the code takes longer to execute and the outcome may vary as Nikita Popov demonstrates in Order of Evaluation in PHP.

Incidentally, there is a trick one may employ to prevent the error notice from cropping up, and at the same time the code will still manage to create the CV — although the technique may impact efficiency by additionally creating a reference to the undefined variable. The trick involves using the taboo global keyword, as follows:

<?php

global $myundef;
null;
;

Note, you can also use keyword static instead of global 🙂

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: