Running phc

Once you have installed phc (see Installation Instructions), run it by typing

phc --help

You should see

phc 0.2.0

Usage: phc [OPTIONS]... [FILES]...

  -h, --help                    Print help and exit
      --full-help               Print help, including hidden options, and exit
  -V, --version                 Print version and exit

GENERAL OPTIONS:
  -v, --verbose                 Verbose output  (default=off)
  -c, --compile                 Compile  (default=off)
      --pretty-print            Pretty print input according to the Zend style
                                  guidelines  (default=off)
      --obfuscate               Obfuscate input  (default=off)
      --run=STRING              Run the specified plugin (may be specified
                                  multiple times)
      --r-option=STRING         Pass option to a plugin (specify multiple flags
                                  in the same order as multiple plugins - 1
                                  option only per plugin)
  -d, --define=STRING           Define ini entry (only affects -c and
                                  --include)
      --no-warnings             Allow warnings to be printed  (default=off)

INPUT OPTIONS:
      --read-xml=PASSNAME       Assume the input is in XML format. Start
                                  processing after the named pass (passes are
                                  ast|hir|mir)
      --include                 Parse included or required files at
                                  compile-time  (default=off)
      --include-harder          Try harder to find included files, possibly
                                  slightly breaking some of PHP's rules
                                  (default=off)

COMPILATION OPTIONS:
  -C, --c-option=STRING         Pass option to the C compile (e.g., -C-g; can
                                  be specified multiple times)
      --extension=EXTENSION     Generate a PHP extension called EXTENSION
                                  instead of a standalone application
      --web-app=CONFIG          Generate a web-application (experimental)
  -O, --optimize=STRING         Optimize  (default=`0')
  -o, --output=FILE             Place executable into file FILE
  -e, --execute                 Run executable after compiling (implies -c)
                               (default=off)

PRETTY PRINTING OPTIONS:
      --next-line-curlies       Output the opening curly on the next line
                                  instead of on the same line  (default=off)
      --no-leading-tab          Don't start every line in between <?php .. ?>
                                  with a tab  (default=off)
      --tab=STRING              String to use for tabs while unparsing
                                  (default=` ')
      --no-hash-bang            Do not output any #! lines  (default=off)

OUTPUT OPTIONS:
      --dump=PASSNAME           Dump input as PHP (although potentially with
                                  gotos and labels) after PASSNAME
      --dump-xml=PASSNAME       Dump input as XML after PASSNAME
      --dump-dot=PASSNAME       Dump input as DOT after PASSNAME
      --list-passes             List of available passes (for PASSNAME)
                               (default=off)

OPTIMIZATION OPTIONS:
      --flow-insensitive        Turn off flow-sensitivity  (default=off)
      --call-string-length=LENGTH
                                Choose the call-string length ('0' indicates
                                  infinite call-string)  (default=`0')

More options are available via --full-help

Now write a very small PHP script, for example

<?php
   echo "Hello world!";
?>

and save it to helloworld.php. Then run phc:

phc --pretty-print helloworld.php

This should output a pretty-printed version of your PHP script back to standard output:

<?php
   echo "Hello world!";
?>

You can see a list of options controlling the style of pretty printing, using the --full-help option.

Compiling executables

phc can compile either executables or extensions. To compile an executable, phc creates C code, which it compiles and links to the PHP embed SAPI. Since it links to PHP, you have access to all of PHP’s large built-in standard library. In order to compile the “hello world” executable from before, run

phc -c helloworld.php -o helloworld

This creates an executable helloworld, which can then be run

./helloworld

If you prefer to run your executable immediately after it compiles, use the -e. phc will compile your program, then immediately execute it. You can also view the C code generated by phc:

phc --generate-c helloworld.php > helloworld.c

Code Optimizaton

One of the advantages of phc is that it can optimize your program. Using the -O flag, you can instruct phc to analyse your source code, and perform optimizations. To optimize:

phc -O2 -c helloworld.php -o helloworld

phc generates C code, which is then compiled by gcc. To see the command passed to gcc by phc, use the -v flag.

If you specify the -O flag, phc will also pass the -O flag to gcc, which will optimize your code further. The argument to the -O flag must therefore be usable by gcc, so it must be any of -O0 (default), -O1, -O2, -O3 or -Os. Consult the gcc manual for more details.

It is also possible to pass command-line arguments to gcc through phc, using the -C flag. For example, to disable inlining of the generated code by gcc, using -fno-inline:

phc -c -O2 helloworld.php -o helloworld -C-fno-inline

Should you wish to bypass phc optimizations, but still have gcc perform optimizations, you can pass the -O flag to gcc via phc‘s -C flag:

phc -c helloworld.php -o helloworld -C-O3

phc also offers a great deal of control over its optimizations, allowing the user to disable individual passes with the --disable flag. The list of passes executed can be obtained by using the --list-passes flag:

phc --list-passes

And any pass(es) in the list can be disabled by simply passing its name as an argument to the --disable flag:

phc -c -O2 --disable=dce,rlb helloworld.php -o helloworld

Optimization does not currently work extremely well. However, contributions are very welcome. See the ‘Contributors’ section for details.

Compiling web applications

Warning

In order to compile web applications, it is currently necessary to alter your php.ini file, or have access to the root account. We welcome suggetions of a different method which avoids these requirements, especially if they would work in a shared hosting environment.

Warning

This section is experimental. Please report any problems.

We have created the command-line option --web-app, which will in the future automate the process of compiling a web application. Unfortunately, for now, please follow these steps.

We describe how to create and install an extension using the C code generated by phc. While we give an overview of creating extensions, significantly more detail can be found in the Zend Extension Writing Tutorial and in Extending and Embedding PHP.

To begin, create a new directory for the extension. We’ll use ext/ in our example. Generate C code from helloworld.php using phc.

phc --extension=helloworld --generate-c helloworld.php > ext/helloworld.c

Create a new file, ext/config.m4, by copying the following, and changing instances of “helloworld” appropriately:

PHP_ARG_ENABLE(helloworld, whether to enable Hello World support,
[ --enable-helloworld   Enable Hello World support])

if test "$PHP_HELLOWORLD" = "yes"; then
  AC_DEFINE(HAVE_HELLOWORLD, 1, [Whether you have Hello World])
  PHP_NEW_EXTENSION(helloworld, helloworld.c, $ext_shared)
fi

In the previous section, we described using the PHP embed SAPI. If you installed a copy of PHP with --enable-embed enabled, it is important NOT to use that version for the following commands. Instead, you should the same version as your webserver uses. From the ext/ directory, run:

phpize --with-php-config=/usr/bin/php-config
./configure --enable-helloworld

Build and install the extension (if you dont have root, refer instead to Alternatives):

make
sudo make install

In your web folder, replace the existing helloworld.php file contents with the following:

<?php
   dl ("helloworld.so");
   __MAIN__ ();
?>

If the dl function is not enabled in your php.ini file, enable it:

enable_dl = On;

Accessing helloworld.php should now work.

Alternatives

Instead of setting enable_dl, you can instead load the extension manually in your php.ini file:

extension=helloworld

You can also avoid installing the extension using sudo make install by adding an alternate extension directory:

extensions_dir="/full/path/to/ext"

Writing and Reading XML

phc can output an XML representation of the PHP script. You can use this representation if you want to process PHP scripts using tools in your desired framework, instead of using phc plugins. After processing the XML representation, phc can convert it back into PHP. To generate an XML version of a PHP script, run

./phc --dump-xml=ast helloworld.php > helloworld.xml

When reading the XML back in, all the usual features of phc are again available; in particular, it is possible to read an XML file, and write PHP syntax. To convert the XML file we just generated back to PHP syntax, run

./phc --read-xml=ast --pretty-print helloworld.xml

The generated XML should use the schema http://www.phpcompiler.org/phc-1.0. However, our XML schema is currently broken.

Internal Representations

After parsing, phc converts a PHP script into an Abstract Syntax Tree (AST) (this is further explained in Traversing the Tree). This is very useful for processing PHP scripts which you wish to convert back into PHP. However, for some tasks, especially program analysis, a simpler form of the PHP script is more suitable. phc offers two other Internal Representations (IRs). The High-level Internal Representation (HIR) simplifies most expressions by assigning them to temporary variables. However, code represented in the HIR is still valid PHP. The Medium-level Internal Representation (MIR) converts HIR statements to simpler components, for example converting control-flow statements like the for-loop, into gotos. To view PHP in any of these forms, use the --dump option:

phc --dump=ast helloworld.php
phc --dump=hir helloworld.php
phc --dump=mir helloworld.php

Nearly all phc options work as well on the HIR and MIR as on the AST. For example, XML can be read and written:

phc --dump-xml=hir | ./myprog | phc --read-xml=hir

Graphical Output

If you have a DOT viewer installed on your system (for example, graphviz), you can view the AST graphically. First, ask phc to output the AST in DOT format:

./phc --dump-dot=ast helloworld.php > helloworld.dot

You can then view the tree (helloworld.dot) using Graphviz. In most Unix/Linux systems, you should be able to do:

dotty helloworld.dot

And you should see the tree; it should look similar to the tree shown in figure Abstract syntax tree for “Hello world”.

_images/helloworld.jpg

Abstract syntax tree for “Hello world”

Including files

phc has initial support for compile-time processing of PHP’s include built-in. Enabling this feature inserts the included statements in the AST in the place of the include statement. Included functions, classes and interfaces become part of the file’s top-level scope. In the event that phc is not able to process the include statement (for example, if the file cannot be found), a warning is issued, and the include statement is left in place. To enable this support, run

./phc --include script_with_includes.php

The include support is intended to mimic PHP’s include built-in, as far as can be achieved at compile time. phc supports:

  • Moving included statements to the point at which include was called. Naturally, these statement’s use the variable scope at the point at which they are included,
  • Preserving __FILE__ and __LINE__ statements,
  • include, and require. If the specified file cannot be found, parsed, or if the argument to include is not a string literal, the include statement is left in place.

phc does not support:

  • Return values in included scripts. We intend to support these in the future. They will likely be supported in a later stage of the compilation process, instead of in the AST,
  • Calling include on anything other than a literal string containing the filename of a local file. This excludes variables and remote files. These may be supported when more static analyses are available,
  • include_once and require_once, as we cannot guarantee that the file to be included is not included elsewhere. These statements will not be processed, and combinations of include or require and include_once or require_once may cause incorrect behaviour with this option set,
  • Updating get_included_files to reflect the included files.