KPHP — a PHP compiler

Overview

KPHP — a PHP compiler

KPHP is a PHP compiler. It compiles a limited subset of PHP to a native binary running faster than PHP.

KPHP was developed at VK.com and maintained as proprietary for years — until open-sourced in late 2020.

Visit the KPHP website with documentation, demos, etc.

Limitations

KPHP wouldn't compile just any random PHP code:

  • It doesn't support features that can't be compiled, such as calling by name or mocks.
  • It won't compile code, that breaks the type system, for instance, mixing numbers and objects in an array.
  • It doesn't have PHP features that VK.com never had a need for, such as SPL classes and XML parsing.
  • Some PHP syntax details just weren't implemented, like generators and anonymous classes.

Read more on this here: KPHP vs PHP differences.

Features over PHP

KPHP analyzes your code as a whole and performs various optimizations focusing on performance and safety:

  • Inferring types of all variables, how to declare them in C++.
  • Compile-time optimizations, such as inlining getters or reducing refcounters flapping.
  • Compile-time checks, including immutability and type system requirements.
  • Runtime optimizations, like constant arrays pre-initing and typed vectors.

Aside from the above, KPHP has coroutines. For now, however, they are almost inapplicable outside of VK code.

Benchmarks

Generally, when your code fits best practices, it runs 3–10 times faster than PHP.

Take a look at the benchmarks page comparing KPHP and PHP performance.
You can also refer to PHP vs KPHP vs C++.

KPHP isn't always faster than PHP, but it can be used to speed up your code by focusing on strict typing and KPHP built-in functions.

"I tried to compile PHP code, but failed"

This situation is quite common. KPHP rarely compiles already existing code without errors. It usually takes some time to rewrite PHP code for it to be compilable with KPHP.

Read more about this in compiling an existing project.

The License

KPHP is distributed under the GPLv3 license, on behalf of VK.com (V Kontakte LLC).

Ask questions and provide feedback

To communicate with KPHP community, use Github issues or public E-Mails available on Github.

You can also take a look at our FAQ page.

Contributing

Please, refer to the Contributing page.

How do I start using KPHP?

Proceed to the installation page and just follow the left menu.

Issues
  • improve composer support (no ifndef + autoload.files)

    improve composer support (no ifndef + autoload.files)

    improve composer support (no ifndef + autoload.files)

    • Added comments to the composer-related code

    • require on the composer-generated autoload.php does not need the #ifndef KPHP anymore

    • Added support for autoload.files See https://getcomposer.org/doc/04-schema.md#files

    When we recognize a require target as a composer-generated autoload.php file, we handle it in a special way: all autoload.files are required in the place of the initial require.

    This transformation can be described like this:

        require_once 'vendor/autoload.php';
        =>
        {
                require_once 'vendor/vkcom/lib/bootstrap.php';
                require_once 'vendor/foo/strings/funcs.php';
                require_once 'vendor/foo/strings/classes.php';
        }
    
    opened by quasilyte 6
  • Improve Exceptions support

    Improve Exceptions support

    Compiler memory consumption comparison:

    old:
    
      memory.rss: 13711200256
      memory.rss_peak: 13970407424
    
      compilation.transpilation_time: 47.7062
      compilation.object_out_size: 39337976
    
    new (with exceptions tracking + @kphp-throws vector inside func info):
    
      memory.rss: 13838069760 (+1%)
      memory.rss_peak: 14024077312 (+0.6%)
    
      compilation.transpilation_time: 46.0325
      compilation.object_out_size: 40028272
    

    Notes:

    • Added support for multiple catch clauses per try block
    • Added \Throwable interface; \Exception now implements \Throwable
    • Added \Error class that implements \Throwable + SPL Exception classes
    • Old KPHP code will generate the same C++ code for the try/catch blocks
    • All code generated code diff is new Exception(...) => __exception_set_location(new Exception(...), __FILE__, __LINE__) and an instance cast of exception var if it's not Throwable
    • Code that catches all possible exceptions does not propagate any (exceptions are tracked)
    • This PR does not implement finally on purpose

    --

    Enabled exceptions inheritance.

    • updated CFG and other passes so they handle the program flow correctly

    • codegen generates 2 new cases for the try/catch ops. If exception class has derived classes, is_a() is used; If exception class has no derived classes, hash comparison is used; When the code catches \Exception class, same codegen is used.

    Exceptions in CFG propagate like this: if try block catches all exceptions, we consider that nothing propagates. Otherwise, we consider all exceptions that can be created inside try block do propagate. We may do exceptions tracking here as well, but it doesn't affect the code generation right now.

    --

    Added PreprocessException pass.

    Add __FILE__ and __LINE__ arguments to the Exception-derived construction call in the PreprocessException pass instead of doing it in the lexer.

    The problem with lexer is that it tries to know about the Exception class and adds these arguments too early.

    If Exception class can be extended, then we don't know whether a new T() expression constructs an exception class. The PreprocessException has class data info, so it can perform this operation with more accuracy.

    We also change the Exception class constructor signature so it's compatible with the PHP version. It doesn't accept the file and line arguments now; to set these fields, a new builtin function is added that is inserted by the compiler.

    This transformation can be described as:

        new T(args...)
        =>
        __exception_set_location(new T(args...), __FILE__, __LINE__)
    

    Where __exception_set_location() call returns the modified exception.

    This patch does not add missing Exception-related features, but it makes it's needed to make the work in that direction possible.

    enhancement 
    opened by quasilyte 5
  • add support for simple ${var} string interpolation expressions

    add support for simple ${var} string interpolation expressions

    This syntax is preferred by some programmers over {$...}.

    The main reasoning behind this change is to make more PHP programs compile as KPHP programs.

    A more compilcated ${} form is not implemented, so this will result in a compile error: "${a[0]}". We may add more complete support for this syntax later.

    Note: inside ${} is subtle and should be handled separately, if ever attempted to be implemented. For example, "${'foo'}" is identical to "$foo". We don't support ${'foo'} variable syntax yet (which is a valid freestanding PHP variable syntax btw).

    Signed-off-by: Iskander Sharipov [email protected]

    opened by quasilyte 5
  • Update installation.md

    Update installation.md

    "tl-compiler" not auto-install with "kphp" package, and user will get "sudo: tl-compiler: command not found" if he follows the instructions clearly

    opened by povargek 4
  • allow `T->regexp` implicit casts even with `strict_types=1`

    allow `T->regexp` implicit casts even with `strict_types=1`

    When strict_types=1 is used, there will be no implicit string->regexp and mixed->regexp conversions, but in fact we don't need them as there are various overloadings that can work with all such types (string, regexp, mixed).

    With this change, it will be possible to use string-typed arguments to preg_* functions when declare(strict_types=1) is used.

    opened by quasilyte 3
  • allow semi-reserved keywords in class member names

    allow semi-reserved keywords in class member names

    Make it possible to use semi-reserved keywords for class methods and constants.

    A new GenTree::get_identifier() method is used in all places where we allow such keywords usage.

    Some code in lexer hack_last_tokens() method is re-arranged, so elseif token is not replaced with else+if tokens in places where we want it to stay a single elseif token.

    Signed-off-by: Iskander Sharipov [email protected]

    enhancement 
    opened by quasilyte 3
  • PostgreSQL or MySQL support

    PostgreSQL or MySQL support

    First of all, I want to thank you for your contribution to the community. But why release a product to the public without the support of at least one database? I understand that you have self-written databases, but they are not available to the community. In General, it is sad that there is no support for PostgreSQL or MySQL. At this stage, this is a product to play a couple of times locally and forget about it.

    opened by johnny-silverhand 3
  • [runtime] make shutdown funcs called even after a timeout

    [runtime] make shutdown funcs called even after a timeout

    The most challenging part is that timeout is catched in a signal handler of the running coroutine (run_context) which then changes the state of the worker and switches the context to exit_context. Running the shutdown handlers inside the run_context before switching it is dangerous as arbitrary PHP code is not guaranteed to be safe for the signal handling context.

    If we run these shutdown handlers inside of the worker context, we may suffer from the exit() calls done inside of the shutdown functions that may cause us to attempt switching the context again and entering a finished state instead of the error state we were in.

    As a solution to this problem, we use a setjmp+longjmp to implement our recovery from the exit() when running shutdown functions.

    We only call shutdown handlers for timeout errors for now. Executing shutdown handlers should not be a problem for some error kinds, but some of them are more challenging (like memory limit errors).

    Fixes #504

    opened by quasilyte 2
  • add to_array_debug() function

    add to_array_debug() function

    In this PR I add an ability to convert standalone shapes and tuples in arrays via old instance_to_array() and new to_array_debug() functions. instance_to_array() was preserved to keep backward compatibility.

    enhancement 
    opened by drdzyk 2
  • get rid of $called-globals for empty source files

    get rid of $called-globals for empty source files

    Such variables generated for tracking whether global scope of file loaded or not. For empty, i.e. doing nothing in global scope, files such variables is unused, so this PR remove it.

    opened by drdzyk 2
  • split building of binary into compiling and linking stages

    split building of binary into compiling and linking stages

    This PR splits building of final binary either server or cli into two stages: compiling and linking. This allow to see profiles separately in resulting table: image

    Also progress bar aren't hang up at 99% percent during linking, because now it shown separately: image

    Another side effect is that now compiling pch stage became more clear since it got name too: image

    opened by drdzyk 2
  • Improve phpt tests

    Improve phpt tests

    Now all phpt tests run in run-once mode. It works like server handling only one request and then terminates. In this way, we can't catch bugs related to per request runtime reinitialization which always happens in production.

    So in this PR:

    1. Run once count option is added, which defines how many requests server in run once mode will handle.
    2. All idempotent phpt tests run twice to check correctness in web-server alike environment with per request runtime reinitialization
    3. All such tests run with option --worker-queries-to-reload 1 to force script memory reallocation after each request. This will help to catch more memory related bugs.
    enhancement 
    opened by DrDet 0
  • kphp not faster than php jit binarytrees php-3 benchmarkgame ?

    kphp not faster than php jit binarytrees php-3 benchmarkgame ?

    I try this script https://benchmarksgame-team.pages.debian.net/benchmarksgame/program/binarytrees-php-3.html (with one modification, replace $n = ($argc == 2) ? $argv[1] : 1; with $n = 16;)

    Php without jit:

    stretch tree of depth 17	 check: 262143
    65536	 trees of depth 4	 check: 2031616
    16384	 trees of depth 6	 check: 2080768
    4096	 trees of depth 8	 check: 2093056
    1024	 trees of depth 10	 check: 2096128
    256	 trees of depth 12	 check: 2096896
    64	 trees of depth 14	 check: 2097088
    16	 trees of depth 16	 check: 2097136
    long lived tree of depth 16	 check: 131071
    php sn.php  1.94s user 0.04s system 99% cpu 1.984 total
    

    Php with jit:

    stretch tree of depth 17	 check: 262143
    65536	 trees of depth 4	 check: 2031616
    16384	 trees of depth 6	 check: 2080768
    4096	 trees of depth 8	 check: 2093056
    1024	 trees of depth 10	 check: 2096128
    256	 trees of depth 12	 check: 2096896
    64	 trees of depth 14	 check: 2097088
    16	 trees of depth 16	 check: 2097136
    long lived tree of depth 16	 check: 131071
    php -dopcache.enable_cli=1 -dopcache.jit_buffer_size=128M sn.php  1.27s user 0.06s system 99% cpu 1.331 total
    

    Kphp:

    stretch tree of depth 17	 check: 262143
    65536	 trees of depth 4	 check: 2031616
    16384	 trees of depth 6	 check: 2080768
    4096	 trees of depth 8	 check: 2093056
    1024	 trees of depth 10	 check: 2096128
    256	 trees of depth 12	 check: 2096896
    64	 trees of depth 14	 check: 2097088
    16	 trees of depth 16	 check: 2097136
    long lived tree of depth 16	 check: 131071
    ./cli  6.34s user 0.11s system 98% cpu 6.570 total
    

    Because it all integer I'm assumming kphp already know about typing? So why it is slower than php version?

    opened by kocoten1992 0
  • Implement ini_get_all()

    Implement ini_get_all()

    Hi, all!

    ini_get() return error when ini-variable not defined. But I won't get any errors for this. I would like to call

    $vars = ini_get_all();
    

    and read defined and not defined variables silently..

    Please implement this method. https://www.php.net/manual/ru/function.ini-get-all.php

    opened by comm644 0
  • RFC: Type aliases

    RFC: Type aliases

    RFC: Type aliases

    Background

    Some VKCOM legacy code is built on associative arrays with lots of parameters. To type such arrays, KPHP have a special shape type that allows to describe the types of each parameter.

    However, in some places, the amount parameters may exceed some large number, which becomes inconvenient when developers need to write a function that takes the same shape.

    <?php
      
    /**
     * @param shape(name: string, age: int, status: string, id: int, other: string) $a
     */
    function set_data($a) { ... }
    
    /**
     * @param [need to copy the entire shape] $a
     */
    function set_data_2($a) { ... }
    

    For situations like this, we want to be able to create an alias for the type, as developers can do in many other languages.

    Aliases kinds

    Since most type aliases in languages are syntactic constructs with native support, their use is allowed anywhere. So, for example, in Hack aliases for types can be used as type hints for function parameters.

    But KPHP is limited by backward compatibility with PHP and KPHP aliases can only work where PHP allows it. The only such place is PHPDoc, where KPHP can use aliases, and it will work in PHP as well.

    It might be possible with some hack to make aliases be classes with lots of magic methods to make it work in PHP, but it doesn't seem worth it, and the PHPDoc-only option is optimal and solves the problem described earlier.

    Solutions

    Since KPHP must remain compatible with PHP, we can't introduce new syntactic constructs as Hack can:

    type Server = shape('name' => string, 'age' => int);
    

    Since this, only options remain within the various comments.

    Static analysis tools

    Psalm

    Psalm has support aliases for types. However, each alias isn't a top-level definition; it's attached to a class:

    /**
     * @psalm-type User = array{name: string, age: int}
     */
    class UserHandler {
        /**
         * @psalm-param User $a
         */
        public function set_data($a) { ... }
    }
    

    To use it inside another class, need to use an import annotation:

    /**
     * @psalm-import-type User from UserHandler
     */
    class UserWatcher {}
    

    Because such aliases are limited to classes, they aren't suitable for KPHP, since a legacy is built on plain functions.

    PHPStan

    PHPStan also has its own syntax for specifying type aliases. It divides them into two types, local, and global.

    Local aliases are completely identical to Psalm.

    Global aliases are set in the config file:

    parameters:
    	typeAliases:
    		Name: 'string'
    		NameResolver: 'callable(): string'
    		NameOrResolver: 'Name|NameResolver'
    

    This solution isn't convenient, since aliases aren't part of the source code.

    Static analysis solutions review

    The solutions above have disadvantages because static analyzers can't introduce their own syntactic constructions and such options are the best they can think of. However, KPHP aren't bound by such restrictions and may introduce new pseudo constructs as long as they're compatible with PHP.

    When prototyping such constructs, however, one must not forget that they must be supported in the IDE. If this isn't possible, then many refactorings in the IDE can become dangerous because they won't consider aliases.

    Pseudo new constructs

    1. Hash comment:

      #typealias User = shape(name: string, age: int)
      

      Pros:

      • Good readability.
      • Looks line native syntax, if highlights #typealias as a keyword.
      • Skip by PHP and not need polyfills.

      Cons:

      • Due to the AST in PhpStorm, there may be problems with parsing and autocompletion in the plugin.
      • In the documentation and other places where there is code, it will be highlighted as a comment.
    2. PHPDoc:

      /** @typealias User = shape(name: string, age: int) */
      

      Pros:

      • Looks line standard for PHP.
      • Easy support in IDE.

      Cons:

      • Looks strange as top level definition.
      • No syntactic construction (class or function) to which the comment is attached.
      • In the documentation and other places where there is code, it will be highlighted as a comment.
    3. typealias function:

      typealias("User", "shape(name: string, age: int)");
      

      Pros:

      • Pretty easy to support in a plugin (since it's a simple function, finding all aliases is out of the box).
      • Looks good as top level definition.
      • Looks like a native class_alias which has support in the IDE.

      Cons:

      • Need to create a polyfill:

        function typealias(string $name, string $type): void {}
        
      • More noise than previous variants.

    Proposal

    Add aliases for types using syntax options 1–3 described earlier (I prefer option 3).

    All aliases for a file must be written before any classes or functions, but after use clauses.

    <?php
      
    namespace VK\Wall;
      
    use VK\Feed;
    
    typealias("User", "shape(name: string, age: int)");
    
    /**
     * @kphp-use-alias User
     *
     * @return User
     */
    function get_user() { ... }
    

    To use an alias, need to add the @kphp-use-alias annotation to PHPDoc. This is necessary to understand at the parsing stage that this type isn't a class, but an alias. This will simplify the implementation in KPHP and the plugin, and make it more obvious to the user that this isn't a class, but some alias for the other type.

    The name for an alias follows the standard rules for identifiers.

    The alias type must be a valid PHPDoc type and can be anything.

    Namespaces

    All aliases, like other top level definitions, are subject to the rules of namespaces. If an alias is defined in some namespace, then its use in another namespace must specify the fully qualified name:

    // 1.php
    <?php
      
    namespace VK\Wall;
    
    typealias("User", "shape(name: string, age: int)");
    
    // 2.php
    <?php
    
    /**
     * @kphp-use-alias \VK\Wall\User
     *
     * @return User
     */
    function get_user() { ... }
    

    The fully qualified name must be specified only in @kphp-use-alias, further uses in this PHPDoc may only use the alias name.

    Since different namespaces can have aliases with the same name, the @kphp-use-alias tag can optionally specify a new name after as:

    <?php
    
    /**
     * @kphp-use-alias \VK\Wall\User
     * @kphp-use-alias \VK\ID\User as IdUser
     *
     * $param IdUser $a
     * @return User
     */
    function get_user($a) { ... }
    

    Backward Incompatible Changes

    None.

    enhancement 
    opened by i582 0
  • Force common runtime template types to be instantiated in runtime sources

    Force common runtime template types to be instantiated in runtime sources

    By default all template types are implicitly instantiated, i.e. the code with substituted types is placed in each translation unit that use the corresponding template. It leads to duplication of common instantiations so many times.

    To get rid of this unnecessary duplicates in this PR explicit template instantiation is applied for common array<T> and optional<T> instantiation patterns.

    This not only reduces the output binary size, but also forces all such instantiations to be compiled with -O3 that potentially can improve performance in some cases.

    optimization 
    opened by DrDet 0
Polaris-SDK for PHP

polaris-php Polaris is an operation centre that supports multiple programming languages, with high compatibility to different application framework. P

liaochuntao 0 Dec 10, 2021
A Simple Language (PHP-Like Syntax)

SL A Simple Language (PHP-Like Syntax) Usage: SL.exe <filename> A 64-bit windows executable is provided (SL.exe) alongside some demo SL code (main.sl)

null 3 Nov 15, 2021
List of Persian Colors and hex colors for CSS, SCSS, PHP, JS, Python, and Ruby.

Persian Colors (Iranian colors) List of Persian Colors and hex colors for CSS, SCSS, PHP, C++, QML, JS, Python, Ruby and CSharp. Persian colors Name H

Max Base 12 Feb 22, 2022
Archived version of PHP 1.99s - released 31st May 1997

php-1.99s An archived copy of PHP 1.99s - originally released 31st May 1997 Visit php-1.99s/README for the original README. Here's how I created this

Simon Willison 2 Nov 24, 2021
PHP Client based on C++ for Polaris

polaris-php Polaris is an operation centre that supports multiple programming languages, with high compatibility to different application framework. P

Polarismesh 6 Jun 20, 2022
Extension for PHP to interface efficiently with a Controller Area Network (CAN bus) 2.0A / 2.0B

PHP-CanBus Extension PHP-canbus is THE extension for PHP on Linux that allows PHP code to interface efficiently with a Controller Area Network (CAN bu

Adamczyk Piotr 4 Jun 9, 2022
Compiler Optimizations Playground

This is (hopefully) the simplest implementation of the classic register-machine intermediate representation (IR) to undertake data and control flow analysis in a compiler middle-end.

null 27 May 31, 2022
PL/0 Compiler Extension(including repeat, for, case, function, real, record and so on)

EX-PL0 PL/0 Compiler Extension(including repeat, for, case, function, real, record and so on) Structure src/PL source code of PL compiler; src/interpr

Chunshuo Qiu 15 Jun 21, 2022
A simple assembler, made primarily for assembling output from my compiler.

Assembler This assembler is not currently meant for general use. It supports only the instructions and features emitted (and used) in my C compiler. I

null 2 Nov 14, 2021
Pure Data patch export to lv2 plugin using heavy compiler + dpf example

Pure Data patch export to lv2 plugin using heavy compiler + dpf example Work in progress - Takes an audio input and writes to a 0.5 seconds buffers. 4

Qwrtst 2 Jun 13, 2022
Set of examples how to use CLion with various unsupported compilers using Custom Defined Compiler feature

About This repository contains: Set of examples how to use CLion with various unsupported compilers using Custom Defined Compiler feature Public set o

JetBrains 30 Jun 15, 2022
A PL/I compiler for Windows NT

PLI-2000 A PL/I compiler for Windows NT This project began as an academic exercise while learning the 'C' language during the summer of 1990, I wanted

null 6 Jun 10, 2022
Practical assignments for the XDU compiler course: The interpreter of function drawing language.

drawing-lang-interpreter Practical assignments for the XDU compiler course: The toy interpreter of function drawing language, written by XDU Zhang Yi(

null 3 Apr 22, 2022
The C source code was RESTORED by disassembling the original executable file OPTIM.COM from the Hi-Tech v3.09 compiler.

The C source code was RESTORED by disassembling the original executable file OPTIM.COM from the Hi-Tech v3.09 compiler. This file is compiled by Hi-Te

null 9 May 23, 2022
A skeleton C compiler in C++

cppc C compiler in C++ Background This is a learning project for Crafting interpreters. Most part of C is supported. Support for pointer is hacky. For

Yujia Qiao 6 Feb 10, 2022
Skyline's fork of yuzu's shader compiler

Skyline Shader Compiler (SSC) A fork of yuzu's shader compiler modified for Skyline's needs with all other changes being upstreamed and changes from y

Skyline 13 Jun 16, 2022
A small DLL that fixes tool's usage of the Halo 3 shader compiler.

h3-shader-compiler-fix A small DLL that fixes tool's usage of the Halo 3 shader compiler. Tool forgot to initialise the compiler before using it, so t

null 7 Jun 20, 2022
Writing a basic compiler frontend following LLVM's tutorial, with complete added supports Hindi and UTF-8 in general

सारस | SARAS Started with following LLVM's tutorial In development, a hobby project only JIT is broken right now, 'jit' branch par code hai uska Compi

Aditya Gupta 4 May 1, 2022