Compile-time location

KPHP allows you to get an exact location, where a cocrete function was called (a previous function at call stack, file name and line number). As if debug_backtrance() was called — but at compile time.

For example, it's possible to implement log_info($message), so that this code

log_info("start calculation");
$arr = [1,2,3,4,5];
foreach ($arr as $v) {
  if ($v > 3)
    log_info("big v=$v");
}
log_info("end calculation");

would print:

start calculation (in demo5 at dev.php:55)
big v=4 (in demo5 at dev.php:59)
big v=5 (in demo5 at dev.php:59)
end calculation (in demo5 at dev.php:61)

Notice, that log_info() prints out a parent (caller) location every time. It differs from time to time, it's unique for every call place.

Here's the implementation:

function log_info(string $message, ?CompileTimeLocation $loc = null) {
  $loc = CompileTimeLocation::calculate($loc);
  echo "$message (in {$loc->function} at {$loc->file}:{$loc->line})\n";
}

In a PHP polyfill, CompileTimeLocation::calculate() calls debug_backtrace() at runtime, but KPHP just appends an implicit argument to every call:

// a regular call
log_info($message);
// is implicitly changed to
log_info($message, new CompileTimeLocation(__FILE__, __METHOD__, __LINE__));

A little notice: like in case of exceptions, a file name in KPHP is relative to a project root (whereas it's absolute in PHP). It makes resulting C++ code not to depend from a tmp path on a build agent, to leave it equal and reusable across machines codegeneration.

By the way, you can pass $loc somewhere further. For example, here's how you can make wrappers around some logger, proxying a call location:

function my_log(CompileTimeLocation $loc = null) {
  $loc = CompileTimeLocation::calculate($loc);
  ...
  generic_log($loc);
}