Compile a sample PHP script

In this section, we will compile a PHP file, launch it as a web server, and examine codegenerated C++ sources.

PHP code for compilation

Save it to ~/kphp-project/my.php (note the path: it will be mapped inside Docker):

<?php
// when launched, shows a form with <input> for entering a number
// when a number is submitted, prints this number squared and a clear button

class InputArgs {
  private $number = null;

  public function isNumberEntered() {
    return $this->number !== null;
  }      

  public function getNumberEntered() {
    return $this->number;
  }

  static function createFromUrl(): self {
    $input = new self;
    if (is_numeric($_GET['number']))
      $input->number = (int)$_GET['number'];
    return $input;
  }
}

function htmlHeader() {
  return "<h1>Hello from KPHP</h1>";
}

function htmlFormWithInput() {
  return "<form method=get>Enter a number: <input type=text value=123 name=number> <input type=submit value=Square></form>";  
}

function htmlNumberSquared($number) {
  $squared = $number ** 2;
  return "$number<sup>2</sup> = $squared<br><a href='/'>Clear</a>";
}

$input = InputArgs::createFromUrl();
if (!$input->isNumberEntered())
  echo htmlHeader(), htmlFormWithInput();
else
  echo htmlHeader(), htmlNumberSquared($input->getNumberEntered());

Compile and run with Docker

If you have installed KPHP via the Docker registry, run the container vkcom/kphp:

docker run -ti -v ~/kphp-project/:/tmp/dev:rw -p 8080:8080 vkcom/kphp

Or, if you have build an image from the Dockerfile locally, run the container kphp:

docker run -ti -v ~/kphp-project/:/tmp/dev:rw -p 8080:8080 kphp

Then just compile my.php and run the server — inside Docker:

kphp /tmp/dev/my.php
./kphp_out/server -H 8080 -f 1

Open http://localhost:8080. Your server is running!

Compile and run without Docker

If you have installed KPHP locally, execute the following:

cd ~/kphp-project
kphp my.php
./kphp_out/server -H 8080 -f 1

Open http://localhost:8080. Your server is running!

Examine C++ sources

Stop the server with Ctrl+C and navigate to the kphp_out/ directory to see its structure:

> cd kphp_out
> ls
kphp/  objs/  server

server is the binary that we have just launched.
kphp/ is a folder with C++ sources. Type ls kphp_out/kphp to see its contents:

  • o_25/ and other o_ with numeric postfixes are folders with functions
  • cl/ is a folder with classes
  • other files and folders are various initializes and runners

For example, take a look at kphp/cl/C@InputArgs.h class:

struct C$InputArgs: public refcountable_php_classes<C$InputArgs> {
  Optional < int64_t > $number{};
  /* ... */
};

Like InputArgs PHP class, it contains a single field. We didn't specify the types in PHP, but KPHP saw that only numbers and null were assigned to the $number field, making it Optional < int64_t > in C++.

Take a look at the htmlHeader() function. In PHP, it was return "<h1>...</h1>". In C++, it looks this way:

string f$htmlHeader() noexcept {
  return v$const_string$usaa89a82146500818;
}

As you can see, KPHP extracted a constant string to a separate variable to avoid creating it at runtime.

It seems confusing, but f$myFn is a valid symbol in C++ code. Using $ eliminates conflicts with native names.

What's next?

Congratulations, you have compiled a small piece of PHP code! Here's what you can do now:

  • Read about type inferring if you're curious about how Optional<int64_t> came to be.
  • Read about instances. If you know about ZVAL in PHP, you may be surprised seeing C++ struct.
  • Set up a new project if you want to start experimenting with KPHP.
  • Try to apply KPHP in already existing projects, if you are ready for one thing.
  • Read out FAQ for the answers to the most common questions.