GithubHelp home page GithubHelp logo

vkcom / kphp Goto Github PK

View Code? Open in Web Editor NEW
1.3K 52.0 82.0 37.83 MB

KPHP — a PHP compiler

Home Page: https://vkcom.github.io/kphp/

License: GNU General Public License v3.0

CMake 0.60% Dockerfile 0.01% C++ 68.66% C 3.89% Shell 0.01% Python 3.25% PHP 23.39% Hack 0.01% Yacc 0.13% Ragel 0.05%
kphp compiler php

kphp's Introduction

macos debian ubuntu

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 a Telegram chat.

You can also take a look at our FAQ page and Roadmap 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.

kphp's People

Contributors

alexk0 avatar andreylzmw avatar apolyakov avatar arseny30 avatar artem avatar astrophysik avatar danil42russia avatar drdet avatar drdzyk avatar eugene536 avatar hidanio avatar i582 avatar ivashkevitch avatar kirugan avatar kojidev avatar kunyavskiy avatar kurpilyansky avatar levlam avatar loskutov avatar lrespublica avatar mkornaukhov03 avatar nikolayzakharevich avatar niyaznigmatullin avatar povargek avatar proggga avatar quasilyte avatar timur-my avatar tindarid avatar troy4eg avatar unserialize avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kphp's Issues

Confusing error message for non-constant index for tuples and shapes

Non-const values are not allowed when indexing stubs and shapes, but errors for such cases are very incomprehensible.

For example:

<?php
function f() {
    $s = shape(["key" => 12, "value" => 1]);
    $key = "value";
    echo $s[$key];
}

f();

Gives the following error:

Compilation error at stage: CheckConversions, gen by node-recalc.cpp:54
  script.php:11  in f
    echo $s[$key];

Type Error [ExprNode $s[.] at script.php:11  in f : any] updated by [ExprNode $s at script.php:11  in f : shape(key:int, value:int)]

The same goes for tuples.

I would like to see an error like this:

Non-const values are not allowed for indexing the shape

Inherited __clone is not called

<?php

class Foo {
  private final function __clone() {
    var_dump(__METHOD__);
  }
}

class Bar extends Foo {
}

$x = new Bar();
$_ = clone $x;

PHP: runtime error: Call to private Foo::__clone()
KPHP: no errors, default (?) cloning is performed

The final private __clone is a trick to make objects non-cloneable.

Note: even if we make the __clone() public (final is irrelevant), it's not going to be called from the derived objects.

<?php

class Foo {
  public function __clone() {
    var_dump(__METHOD__);
  }
}

class Bar extends Foo {}
class Baz extends Bar {}

$x = new Baz();
$_ = clone $x;

PHP: prints "Foo::__clone"
KPHP: prints nothing

Confusing error message when using a constant of a nonexistent class

Code Example

<?php

use Some\NonExisting;

function f() {
    $a = NonExisting::C;
    echo $a;
}

f();

Actual Behavior

cfg doesnt handle this type of operation: 19
Output
Compilation error at stage: Calc control flow graph, gen by cfg.cpp:1017
 script.php:6  in f
   $a = NonExisting::C;

cfg doesnt handle this type of operation: 19


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fatal error at stage: Calc control flow graph, gen by cfg.cpp:1018
 script.php:6  in f
   $a = NonExisting::C;

Assertion 0 failed

Compilation failed.
It is probably happened due to incorrect or unsupported PHP input.
But it is still bug in compiler.
[pid 9515] [time 1619890522] SIGABRT caught, terminating program
[pid 9515] [time 1619890522] errno = No such file or directory
[pid 9515] [time 1619890522] 
------- Register Values -------
[pid 9515] [time 1619890522] RIP=0x00007FDCF3D0618B RSP=0x00007FFFD5571F90 RBP=0x00007FFFD55722E0 RDI=0x0000000000000002 RSI=0x00007FFFD5571F90 RDX=0x0000000000000000 RCX=0x0000000000000008 R8=0x0000000000000000 R9=0x00007FFFD5571F90 R10=0x0000000000000008 RBX=0x00007FDCF3C91780 RAX=0x0000000000000000 CR2=0x0000000000000000 R11=0x0000000000000008 R12=0x0000000000000000 R13=0x0000000000000000 R14=0x00007FFFD5575EB0 R15=0x0000000000000003 
[pid 9515] [time 1619890522] 
------- Stack Backtrace -------
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_Z15print_backtracev+0x57)[0xc834b0]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp[0xc83aef]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x15420)[0x7fdcf4232420]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0xcb)[0x7fdcf3d0618b]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x12b)[0x7fdcf3ce5859]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_Z20on_compilation_errorPKcS0_iS0_12AssertLevelT+0x28e)[0xc1c42e]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN3cfg3CFG10create_cfgE13VertexAdaptorIL9Operation1EEPNS_4NodeES5_bb+0x3ab0)[0xa94386]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN3cfg3CFG10create_cfgE13VertexAdaptorIL9Operation1EEPNS_4NodeES5_bb+0x104e)[0xa91924]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN3cfg3CFG10create_cfgE13VertexAdaptorIL9Operation1EEPNS_4NodeES5_bb+0x1de)[0xa90ab4]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN3cfg3CFG10create_cfgE13VertexAdaptorIL9Operation1EEPNS_4NodeES5_bb+0x3812)[0xa940e8]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN3cfg3CFG16process_functionE2IdI12FunctionDataE+0x174)[0xa97012]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN9CFGBeginF7executeE2IdI12FunctionDataER10DataStreamI14FunctionAndCFGE+0xb9)[0xa97a73]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN4PipeI9CFGBeginF10DataStreamI2IdI12FunctionDataEES1_I14FunctionAndCFGEE13process_inputEOS4_+0x57)[0xb809f9]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN16PipeWithProgressI9CFGBeginF10DataStreamI2IdI12FunctionDataEES1_I14FunctionAndCFGEE13process_inputEOS4_+0x3d)[0xb80979]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN8PipeTaskI4PipeI9CFGBeginF10DataStreamI2IdI12FunctionDataEES2_I14FunctionAndCFGEEE7executeEv+0x5d)[0xb9e609]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_ZN18OneThreadScheduler7executeEv+0xd0)[0xb4b724]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_Z16compiler_executeP16CompilerSettings+0xbc0)[0xb6cba5]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(main+0x2ab7)[0x9136c6]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7fdcf3ce70b3]
/mnt/c/projects/books/kphp/objs/bin/kphp2cpp(_start+0x2e)[0x90f8be]
[pid 9515] [time 1619890522] -------------------------------
[pid 9515] [time 1619890522] kphp2cpp compiled at May  1 2021 13:56:06 MSK by gcc 9.3.0 64-bit after commit 95e0d620f88898643c39f83839836adbebe8ea00 [pid 9515] [time 1619890522] 

Process finished with exit code 1

Expected Behavior

Class NonExisting was not found.

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.

Some arguments in defined() cause a compiler crash

Code that causes the crash:
https://github.com/nikic/PHP-Parser/blob/37ac4ea9c20ffd121ea63b7a4532ad730305f11c/lib/PhpParser/Lexer.php#L492

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Inline defines pass, gen by inline-defines-usages.cpp:19
  vendor/nikic/php-parser/lib/Lexer.php:489  in PhpParser\Lexer::createTokenMap
    } elseif (defined($name = Tokens::class . '::' . $name)) {

wrong arguments in 'defined'

dl_assert failed [vertex-adaptor.h:68: vertex_inner<Op>& VertexAdaptor<Op>::operator*() [with Operation Op = (Operation)1]]: impl != nullptr
[pid 27381] [time 1619485799] SIGABRT caught, terminating program
[pid 27381] [time 1619485799] errno = No such file or directory
[pid 27381] [time 1619485799] 
------- Register Values -------
[pid 27381] [time 1619485799] RIP=0x00007F5BD7CDB18B RSP=0x00007F5BAE7F9450 RBP=0x00007F5BAE7F96E0 RDI=0x0000000000000002 RSI=0x00007F5BAE7F9450 RDX=0x0000000000000000 RCX=0x00007F5BD7CDB18B R8=0x0000000000000000 R9=0x00007F5BAE7F9450 R10=0x0000000000000008 RBX=0x00007F5BAE7FB700 RAX=0x0000000000000000 CR2=0x0000000000000000 R11=0x0000000000000246 R12=0x0000000000CB816B R13=0x00007FFFF0D1CC9F R14=0x00007FFFF0D1CCA0 R15=0x00007F5BAE7F9F80 
[pid 27381] [time 1619485799] 
------- Stack Backtrace -------
kphp(_Z15print_backtracev+0x53)[0xbe2018]
kphp[0xbe2645]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x153c0)[0x7f5bd838f3c0]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0xcb)[0x7f5bd7cdb18b]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x12b)[0x7f5bd7cba859]
kphp(_Z19dl_get_empty_sigsetv+0x0)[0xba3c90]
kphp[0xba3bc1]
kphp(_ZN13VertexAdaptorIL9Operation1EEdeEv+0x37)[0x8ceb13]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0x7a)[0xa93837]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEvR13VertexAdaptorIL9Operation1EEPT_+0xde)[0xa9389b]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassL9Operation5EEvR13VertexAdaptorIXT0_EEPT_+0x36)[0xb08cab]
kphp(_Z17run_function_passI23InlineDefinesUsagesPassEN18FunctionPassTraitsIT_E14GetDataReturnTE2IdI12FunctionDataEPS2_+0x141)[0xb04af3]
kphp(_ZN13FunctionPassFI23InlineDefinesUsagesPassE7executeE2IdI12FunctionDataER10DataStreamIS4_E+0x5e)[0xafa8f0]
kphp(_ZN4PipeI13FunctionPassFI23InlineDefinesUsagesPassE10DataStreamI2IdI12FunctionDataEES7_E13process_inputEOS6_+0x53)[0xaf3b5d]
kphp(_ZN16PipeWithProgressI13FunctionPassFI23InlineDefinesUsagesPassE10DataStreamI2IdI12FunctionDataEES7_E13process_inputEOS6_+0x39)[0xaf3ae5]
kphp(_ZN8PipeTaskI4PipeI13FunctionPassFI23InlineDefinesUsagesPassE10DataStreamI2IdI12FunctionDataEES8_EE7executeEv+0x41)[0xb0ceff]
kphp(_ZN9Scheduler19thread_process_nodeEP4Node+0x4c)[0xac72f2]
kphp[0xac734a]
kphp[0xac7921]
kphp[0xac7776]
kphp[0xac7584]
kphp(_ZN9Scheduler14thread_executeEP13ThreadContext+0x9c)[0xac73f6]
kphp(_Z24scheduler_thread_executePv+0x2b)[0xac6cda]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x9609)[0x7f5bd8383609]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x43)[0x7f5bd7db7103]
[pid 27381] [time 1619485799] -------------------------------
[pid 27381] [time 1619485799] kphp2cpp compiled at Apr 23 2021 14:57:18 MSK by gcc 8.4.0 64-bit after commit 385ce650dee46ea602482c80e9ecae4ec5d01245 [pid 27381] [time 1619485799]

Assert triggers due to the phpdoc parsing error

Reproducer (note that the phpdoc for $actionBase is remarkable):

<?php

class Parser {
    /** @var int[] Map of states to a displacement into the $action table. The corresponding action for this
     *             state/symbol pair is $action[$actionBase[$state] + $symbol]. If $actionBase[$state] is 0, the
        action is defaulted, i.e. $actionDefault[$state] should be used instead. */
    public $actionBase;

    protected function assertTriggersHere(array $xs): array {
        return array_map(function ($x) { return $x+1; }, $xs);
    }
}

It will give a parse error for phpdoc and then fail at assertTriggersHere.

A real-world example where we get such crash:
https://github.com/nikic/PHP-Parser/blob/0cee2088eab93700691fbdeb878554110b03dd9c/lib/PhpParser/ParserAbstract.php#L61-L63

It may be related to a bad phpdoc parse error recovery or something else. I haven't done any real investigations yet.

Backtrace for nerds
dl_assert failed [vertex-adaptor.h:58: vertex_inner* VertexAdaptor::operator->() [with Operation Op = (Operation)35]]: impl != nullptr
[pid 26317] [time 1609246353] SIGABRT caught, terminating program
[pid 26317] [time 1609246353] 
------- Register Values -------
[pid 26317] [time 1609246353] RIP=0x00007F7EEE390E97 RSP=0x00007F7ED1872C20 RBP=0x00007F7ED1872EA0 RDI=0x0000000000000002 RSI=0x00007F7ED1872C20 RDX=0x0000000000000000 RCX=0x00007F7EEE390E97 R8=0x0000000000000000 R9=0x00007F7ED1872C20 R10=0x0000000000000008 RBX=0x00000000007D53A2 RAX=0x0000000000000000 CR2=0x0000000000000000 R11=0x0000000000000246 R12=0x0000000000000000 R13=0x000000000000003A R14=0x0000000000985880 R15=0x00000000007D53B3 
[pid 26317] [time 1609246353] 
------- Stack Backtrace -------
../kphp[0x6ffd1c]
../kphp[0x70050f]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x12890)[0x7f7eeee7c890]
/lib/x86_64-linux-gnu/libc.so.6(gsignal+0xc7)[0x7f7eee390e97]
/lib/x86_64-linux-gnu/libc.so.6(abort+0x141)[0x7f7eee392801]
../kphp[0x4e484a]
../kphp[0x6dc408]
../kphp[0x6912c3]
../kphp(_ZN7GenTree12get_expr_topEb+0x1418)[0x6a5ba8]
../kphp(_ZN7GenTree13get_binary_opEib+0x2e7)[0x6a6047]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree13get_binary_opEib+0x80)[0x6a5de0]
../kphp(_ZN7GenTree10get_returnEv+0x4c)[0x6a789c]
../kphp(_ZN7GenTree13get_statementEN2vk11string_viewE+0x585)[0x6aa275]
../kphp(_ZN7GenTree7get_seqERSt6vectorI13VertexAdaptorIL9Operation1EESaIS3_EE+0x54)[0x6ad3a4]
../kphp(_ZN7GenTree7get_seqEv+0x2c)[0x6ad40c]
../kphp(_ZN7GenTree13get_statementEN2vk11string_viewE+0x7ad)[0x6aa49d]
../kphp(_ZN7GenTree12get_functionE9TokenTypeN2vk11string_viewE17FunctionModifiersPSt6vectorI13VertexAdaptorIL9Operation43EESaIS7_EE+0xbd6)[0x6a3cf6]
../kphp(_ZN7GenTree16get_class_memberEN2vk11string_viewE+0x169)[0x6a6a99]
../kphp(_ZN7GenTree13get_statementEN2vk11string_viewE+0x64e)[0x6aa33e]
../kphp(_ZN7GenTree7get_seqERSt6vectorI13VertexAdaptorIL9Operation1EESaIS3_EE+0x54)[0x6ad3a4]
../kphp(_ZN7GenTree7get_seqEv+0x2c)[0x6ad40c]
../kphp(_ZN7GenTree13get_statementEN2vk11string_viewE+0x7ad)[0x6aa49d]
../kphp(_ZN7GenTree9get_classEN2vk11string_viewE9ClassType+0x42e)[0x6acf4e]
../kphp(_ZN7GenTree13get_statementEN2vk11string_viewE+0x16d)[0x6a9e5d]
../kphp(_ZN7GenTree7get_seqERSt6vectorI13VertexAdaptorIL9Operation1EESaIS3_EE+0x54)[0x6ad3a4]
../kphp(_ZN7GenTree3runEv+0x2e6)[0x6ad756]
../kphp(_ZN6ParseF7executeESt4pairI2IdI7SrcFileESt6vectorI5TokenSaIS5_EEER10DataStreamIS1_I12FunctionDataEE+0xf1)[0x633d91]
../kphp(_ZN16PipeWithProgressI6ParseF10DataStreamISt4pairI2IdI7SrcFileESt6vectorI5TokenSaIS7_EEEES1_IS3_I12FunctionDataEEE13process_inputEOSA_+0x6d)[0x67caed]
../kphp(_ZN8PipeTaskI4PipeI6ParseF10DataStreamISt4pairI2IdI7SrcFileESt6vectorI5TokenSaIS8_EEEES2_IS4_I12FunctionDataEEEE7executeEv+0x57)[0x66ae57]
../kphp(_ZN9Scheduler14thread_executeEP13ThreadContext+0x271)[0x653311]
../kphp(_Z24scheduler_thread_executePv+0x10)[0x6533e0]

Confusing error for the method implementation with mismatching param name

<?php

interface I {
    /** @param int $x */
    public function f($x);
}

class C implements I {
    public function f($y) { // Note: it's $y, not $x
        return $y + 1;
    }
}

$c = new C();
var_dump($c->f(10)); // prints 11 in PHP

Compiling this script with KPHP will result in an error:

Compilation error [gen by $KPHP_ROOT/compiler/pipes/prepare-function.cpp at 303]
In stage = [Prepare function]:
  [file = example.php]
  [function = C::f:9]
  [line = 9]
//   9:
@param for unexisting argument $x

Compilation terminated due to errors

If C and I defined in different files (the usual case), this error is very confusion. It tells that C::f has some @param for non-existing parameter $x, but in fact it has no phpdoc (it also doesn't have $x parameter).

We should either permit param names to mismatch as in PHP or give a better compilation error, like:

$y param name should be $x, as defined in the I interface

Access static method from an instantiated object

<?php

class SomeClass {
  static function someMethod(): string {
    return 'some value';
  }
}

$a = new SomeClass();
echo $a->someMethod();

PHP 7.2.22 output:

❯ php test.php
some value

KPHP:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Preprocess function, gen by preprocess-function.cpp:558
  at  test.php:10
  //  echo $a->someMethod();
Unknown function ->someMethod() of SomeClass

Private constants produce a CE

Here is a minimal example to reproduce a compilation error Can't access private const c#A$$C given by KPHP.

<?php

class A {
    private const C = 10;
    private $a = [self::C];
    private $b = self::C;
}

new A();

Parsing error of file with HTML (even just `\n` at the beginning) and namespace

Minimal example:

<!-- Line breaks here, github removes them automatically. -->
<?php

namespace Foo;

Error:

Compilation error at stage: Parse file, gen by gentree.cpp:1649
  test.php:4
    namespace Foo;

Failed to parse statement. Expected `;`

This currently affects tests as we cannot specify a namespace in a file with @ok and other tags.

Smart cast fails in AND-chain

Consider following example:

<?php
main();

function main() {
  $x = null;
  if (true) {
    $x = 1;
  }

  $y = $x && foo($x);
}

function foo(int $x): bool {
  return $x > 0;
}

Code translation fails with the following:

+----------------------+
| TYPE INFERENCE ERROR |
+----------------------+
Incorrect type of the arg #0 ($x) at function: foo
Expected type:	int
Actual type:	int|null
+-------------+
| STACKTRACE: |
+-------------+
arg #0 ($x) : int|null   at function: foo
$x : int|null            at function: foo
arg #0 ($x) : int|null   at function: foo
$x : int|null            at test.php: main:10
null                     at test.php: main:5

while this snippet works just fine:

<?php

main();

function main() {
  $x = null;
  if (true) {
    $x = 1;
  }

  $y = false;
  if ($x) {
    $y = foo($x);
  }
}

function foo(int $x): bool {
  return $x > 0;
}

preg_match_all PREG_OFFSET_CAPTURE results mismatch for php7.4+ and above

https://3v4l.org/kmbT9

<?php
var_dump(preg_match_all('/(a)?/', 'a', $matches, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE));
var_dump($matches);

Probably related to: https://bugs.php.net/bug.php?id=73948 (https://bugs.php.net/bug.php?id=61780)
Fix: php/php-src@f53e739

Should be fixed in KPHP as well.

Output for 7.4.0 - 7.4.16, 8.0.0 - 8.0.3

int(2)
array(2) {
  [0]=>
  array(2) {
    [0]=>
    array(2) {
      [0]=>
      string(1) "a"
      [1]=>
      int(0)
    }
    [1]=>
    array(2) {
      [0]=>
      string(0) ""
      [1]=>
      int(1)
    }
  }
  [1]=>
  array(2) {
    [0]=>
    array(2) {
      [0]=>
      string(1) "a"
      [1]=>
      int(0)
    }
    [1]=>
    array(2) {
      [0]=>
      string(0) ""
      [1]=>
      int(-1)
    }
  }
}

Output for 7.3.0 - 7.3.27

int(2)
array(2) {
  [0]=>
  array(2) {
    [0]=>
    array(2) {
      [0]=>
      string(1) "a"
      [1]=>
      int(0)
    }
    [1]=>
    array(2) {
      [0]=>
      string(0) ""
      [1]=>
      int(1)
    }
  }
  [1]=>
  array(2) {
    [0]=>
    array(2) {
      [0]=>
      string(1) "a"
      [1]=>
      int(0)
    }
    [1]=>
    string(0) ""
  }
}

Forbid use count() on not countable types

It's necessary to forbid usage of count() function during code translation for any object whose type is not countable (int, float, bool, etc.), because there's no use for that if we know that the type is not countable for sure.

Need to fix design of shapes - they must allow to be created with empty array [], must accept [] as default value of parameter, must not require to be wrapped in shape() call when created

Shapes are good, but they are not as useful as they could be, because they force to change code, and changed code to the worse.

An example, we had a function in PHP accepting options, with empty options as default

function withOptions($options = []) {
  $timestamp = $options['timestamp'] ?? 0;
  $exotic = $options['exotic'] ?? false;
  echo 'timestamp='.$timestamp.' exotic='.(int)$exotic.'<br/>';
}

withOptions(['timestamp'=>15]);
withOptions(['exotic'=>true]);
withOptions(['timestamp'=>10, 'exotic'=>true]);
withOptions([]);
withOptions();

Everything was good and terse, except we wanted KPHP compiler to check that only allowed options are passed, and generate much more efficient code using static typing.

So what we wanted is that our code does not change at all, we only wanted annotation that forces static type checks, like this.

/**
 * @param shape(exotic:?bool, timestamp:?int) $options
 */
function withOptions($options = []) {
  $timestamp = $options['timestamp'] ?? 0;
  $exotic = $options['exotic'] ?? false;
  echo 'timestamp='.$timestamp.' exotic='.(int)$exotic.'<br/>';
}

withOptions(['timestamp'=>15]);
withOptions(['exotic'=>true]);
withOptions(['timestamp'=>10, 'exotic'=>true]);
withOptions([]);
withOptions();

Now KPHP compiler has enough information to static check and generate efficient code here.

Instead, with current shapes design, we need to change our code to be

/**
 * @param ?shape(exotic:?bool, timestamp:?int) $options
 */
function withOptions($options = null) {
  $timestamp = $options ? ($options['timestamp'] ?? 0) : 0;
  $exotic = $options ? ($options['exotic'] ?? false) : false;
  echo 'timestamp='.$timestamp.' exotic='.(int)$exotic.'<br/>';
}

withOptions(shape(['timestamp'=>15]));
withOptions(shape(['exotic'=>true]));
withOptions(shape(['timestamp'=>10, 'exotic'=>true]));
withOptions();

This make shapes much less usable than they could be.

Context line is not always shown on error

If the error is contained in the line, which is the last in the file, the context line is not displayed.

For example:

<?php
echo $b;
Compilation error at stage: Final check, gen by final-check.cpp:633
  script.php:5
    

Variable $b has Unknown type
<?php
echo $b;
// empty line
Compilation error at stage: Final check, gen by final-check.cpp:633
  script.php:5
    echo $b;

Variable $b has Unknown type

PHP 8

PHP 8.x added a lot of different things and changed a lot of behaviors.
This issue is tracking the status of PHP 8 implementation in KPHP.

The following emoji will be used to denote the task status:

  • 🔆 — high priority
  • 🔅 — low priority
  • 🔸 — breaks backward compatibility
  • 🔺 — will not be changed in KPHP
  • ⏳ — syntax is supported at the parser level
  • 🔨 — in progress

PHP 8.0

Added

New syntax

  • Attributes (RFC) 🔆 | #333
  • Union types in type hints (RFC) | #734
  • nullsafe operator (?->) (RFC) 🔆 | 🔨 #686
  • static return typehint (RFC)
  • match expression (RFC) 🔆 | 🔨 #303 #724
  • throw can be used as an expression (RFC) 🔅
  • Block catch without variable (RFC) | #309
  • Named arguments (RFC) 🔆 | 🔨 #317 #853
  • Declaring properties in the constructor (RFC) 🔆 | #310
  • Trailing comma in parameter lists and closure use list (RFC), (RFC) | 🔨 #308 #664

Other

  • Stringable interface (RFC) 🔅
  • Ensure correct signatures of magic methods (RFC)
  • Add str_starts_with and str_ends_with (RFC) 🔅
  • Add str_contains (RFC) 🔅

Changed

  • Saner numeric strings (RFC) 🔸
  • Saner string to number comparisons (RFC) 🔸
  • Locale-independent float to string cast (RFC) 🔸
  • Sorting now stable (RFC) 🔸
  • Names in the namespace are treated as a single token (RFC)
  • Deferencable changes and arbitrary expressions in new/instanceof (RFC)
  • Access ::class on object (RFC) 🔅
  • Concatenation precedence (RFC) 🔸
  • Arrays starting with a negative index (RFC) 🔸

Removed

  • Remove (real) cast (without separate RFC) 🔺

  • Remove (unset) cast (without separate RFC) 🔺

  • Remove {} access (without separate RFC) 🔺

PHP 8.1

Added

New syntax

  • Readonly properties (RFC) | #307
  • never type (RFC) | #337
  • Enums (RFC) 🔆 | 🔨 #824
  • Final class constants (RFC) | #336
  • ⏳ First-class callable syntax (RFC) 🔨
  • ⏳ Explicit octal integer literal notation (RFC) 🔅 🔨
  • Pure intersection types (RFC) 🔺

Other

  • array_is_list(array $array): bool (RFC)

Changed

  • New in initializers (RFC)
  • Array unpacking with string keys (RFC) 🔸
  • Static variables in inherited methods (RFC) 🔺

PHP 8.2

Added

New syntax

  • ⏳ Readonly classes (RFC) 🔨
  • ⏳ Disjunctive Normal Form Types (RFC) 🔨
  • Allow null and false as stand-alone types (RFC) | commit
  • ⏳ Add true type (RFC) 🔨
  • ⏳ Constants in Trait (RFC) 🔨

Other

  • Add flag FILTER_FLAG_GLOBAL_RANGE

Changed

  • Deprecate dynamic properties (RFC)
  • Deprecate ${} string interpolation (RFC)
  • DateTime::createFrom(Im|M)utable return type changed from DateTime to static
  • strtolower(), strtoupper(), stristr(), stripos(), strripos(), lcfirst(), ucfirst(), ucwords(), and str_ireplace() are no longer locale-sensitive
  • str_split() returns an empty array for an empty string now
  • Callables that are not accepted by the $callable() syntax (but are accepted by call_user_func()) are deprecated:
    • self::method
    • parent::method
    • "static::method"
    • ["self", "method"]
    • ["parent", "method"]
    • ["static", "method"]
    • ["Foo", "Bar::method"]
    • [new Foo, "Bar::method"]

\define doesn't work in KPHP

<?php

\define('C', 10);
var_dump(C);
Compilation error at stage: Preprocess function, gen by preprocess-function.cpp:570
  hello.php:3
    \define('C', 10);

Unknown function define()

Same for \defined() and probably all other builtin function-like expressions.

Future of `|null` type

Consider following code:

<?php

main();

function main() {
  $future = null;
  if ($some_check()) {
    $future = fork(foo());
  }
  ... // some work
  $result = null;
  if ($future !== null) {
    $result = wait($future);
  }
  echo $result;
}

function foo(): int {
  return 0;
}

Translation of the code above fails with type mismatch:

Expected type:	future< Unknown >|false
Actual type:	future< int >|null

I can see two problems here:

  1. Currently wait function has following signature:

    function wait($id :<=: future(any) | false) ::: ^1[*] | null;
    

    So it does not accept any future that has |null as type. It's necessary to remember that any future should be false by default, not null, which is quite annoying.

  2. I expect that$future !== null should produce a smart cast of $future and drop |null, but it doesn't.

bcmul ignores scale param

This was the behavior in PHP7.2 and prior.
Starting from PHP7.3 and above, scale is not ignored anymore.
https://bugs.php.net/bug.php?id=66364
Affected test: phpt/dl/483_bcmath

PHP7.2:

<?php

var_dump(bcmul('-1', '-1', 10)); // => 1

PHP7.3+:

<?php

var_dump(bcmul('-1', '-1', 10)); // => 1.0000000000

Interface method is not implemented via multi-level abstract class inheritance

This don't work:

<?php

interface Iface {
  function f();
}

abstract class AbstractBase {
  public function f() {}
}

abstract class AbstractBase2 extends AbstractBase {}

class Concrete extends AbstractBase2 implements Iface {}

$c = new Concrete();

This, hovewer, does work:

<?php

interface Iface {
  function f();
}

abstract class AbstractBase {
  public function f() {}
}

class Concrete extends AbstractBase implements Iface {}

$c = new Concrete();

Diff:

- class Concrete extends AbstractBase2 implements Iface {}
+ class Concrete extends AbstractBase implements Iface {}

Error message:

Compilation error at stage: Generate virtual methods of interfaces/base classes, gen by virtual-method-generator.cpp:122
  hello.php:0  in Iface::f

You should override abstract method: `Iface::f` in class: `Concrete`

Could be a regression.
This deserves a dedicated test when this issue is fixed (so we don't break it again).

Wrong `rl_type` for `new B` in `echo`

Minimal example

class B {
  public function __toString(): void {
    echo 1;
  }
}

echo new B();

Expected

Сompile-time error about using the result of a void function.

Actual

At the moment we will give an error that the return type of __toString is not a string,
however, the void check will happen earlier and should be issued first, but it is not issued.
Apparently, this is due to an incorrect calculation of rl_type, which is why the condition
is not match any in FixReturnsPass.

Confusing error message for undefined constants

<?php

var_dump(UNDEFINED_CONST);

KPHP error:

Compilation error at stage: Preprocess function, gen by preprocess-function.cpp:426
  hello.php:3
    var_dump(UNDEFINED_CONST);

Unexpected function pointer: UNDEFINED_CONST

Maybe we need to mention that it could also be a result of undefined const:

Unexpected function pointer or undefined const: UNDEFINED_CONST

Or rethink this error message completely (do we need to support this kind of unquoted func names at all?).

Can't use static methods in derived constructors

<?php

class Foo {
  public function __construct() {
    self::f();
  }

  private static function f() {}
}

class Bar extends Foo {}

$bar = new Bar();

Bar gets a constructor from Foo. Due to the details of how we resolve self and inherit the constructor, we fail to resolve self::f() inside Foo to Foo::f.

KPHP error:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Resolve self/static/parent, gen by resolve-self-static-parent.cpp:92
  hello.php:5  in Foo::__construct
    self::f();

using `self/parent/static` is prohibited in non static methods

The manual workaround is to spell the class name explicitly:

class Foo {
  public function __construct() {
    Foo::f();
  }

  private static function f() {}
}

class Bar extends Foo {}

Compilation failure for unused class used in instanceof expr

<?php

class Bar {}
class Foo extends Bar {}

function f(Bar $f) {
  var_dump($f instanceof Foo);
}

f(null);

// - Foo is "unused" and will not be generated
// - instanceof produces unconditional class_dep on Foo
// - we get Can't find header cl/[email protected] required by o_0/f.h + compiler crash

class_dep is added here:

if (auto instanceof = vertex.try_as<op_instanceof>()) {
current_function->class_dep.insert(instanceof->derived_class);
}

Possible solutions:

  • Don't add class_dep for unused classes?
  • Don't try to add a header for unused class?
  • Mark class as used if it was reachable from instanceof from a used function?
  • ...

I'll reference another related problem to this issue.

Class name resolving error (when namespace and class names collide?)

Reproducer:

https://github.com/quasilyte/kphp-compile-errors/tree/master/namespace_resolving

git clone https://github.com/quasilyte/kphp-compile-errors.git
cd kphp-compile-errors/namespace_resolving
composer install
php -f main.php # works fine
kphp --composer-root $(pwd) main.php # gives a compile-time error

Tried without composer as well; it also fails.

Error message:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Apply phpdocs, gen by phpdoc.cpp:627
  lib/BinaryExpr/BinaryPlus.php:5  in Ast\BinaryExpr\BinaryPlus::__construct
    use Ast\BinaryExpr;

Could not find class Ast\BinaryExpr\Expr


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Apply phpdocs, gen by parse-and-apply-phpdoc.cpp:75
  lib/BinaryExpr/BinaryPlus.php:5  in Ast\BinaryExpr\BinaryPlus::__construct
    use Ast\BinaryExpr;

Failed to parse @param of Ast\BinaryExpr\BinaryPlus::__construct


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Apply phpdocs, gen by phpdoc.cpp:627
  lib/BinaryExpr/BinaryPlus.php:5  in Ast\BinaryExpr\BinaryPlus::__construct
    use Ast\BinaryExpr;

Could not find class Ast\BinaryExpr\Expr


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compilation error at stage: Apply phpdocs, gen by parse-and-apply-phpdoc.cpp:75
  lib/BinaryExpr/BinaryPlus.php:5  in Ast\BinaryExpr\BinaryPlus::__construct
    use Ast\BinaryExpr;

Failed to parse @param of Ast\BinaryExpr\BinaryPlus::__construct

Compilation terminated due to errors

Support Apple M1 chipset

Now, compiling kphp from sources fails on M1. homebrew has other paths, M1 doesn't support SIMD and several similar problems.
Finally, I got it compiled (basically by commenting cpp code), but couldn't get it work. It just hangs around swap_context(), even in cli mode.
I found this library on Github, but couldn't get in compiled also.

timelib can't be compiled with a newer gcc

Reported by one of the users.

[ 42%] Building CXX object CMakeFiles/kphp2cpp_src.dir/compiler/data/lib-data.cpp.o
[ 42%] Building C object _deps/kphp-timelib-build/CMakeFiles/kphp-timelib.dir/interval.c.o
cc1: error: command-line option ‘-Wno-redundant-move’ is valid for C++/ObjC++ but not for C [-Werror]
cc1: error: command-line option ‘-Wno-redundant-move’ is valid for C++/ObjC++ but not for C [-Werror]
gcc version 10.3.1
uname -a
Linux hostname 5.10.19-1032.native #1 SMP Wed Mar 3 13:57:49 PST 2021 x86_64 GNU/Linux

It looks like we forward -Wno-redundant-move flag to the timelib build options.

GCC compile fail on `var_dump` with `shape`

Code example:

<?php

/**
 * @return shape(foo: int, boo: string)
 */
function f() {
    return shape(["foo" => 1, "boo" => "hello"]);
}

$a = f();
var_dump($a);

Actual Behavior:

...
not known conversion from shape<...

Expected Behavior:

No error or compile time warning.

KPHP allows calling methods on null instances

<?php

class Foo {
  public function f() {
    var_dump("OK");
  }
}

function test() {
  /** @var Foo */
  $foo = null;
  $foo->f();
}

test();

PHP:

Stack trace:
#0 example.php(15): test()
#1 {main}
  ...

KPHP:

string(2) "OK"

KPHP will produce a warning if we access an object via $this, but otherwise there will be no warnings or errors.

Sugar aliases for `array_reserve`

Currently function array_reserve has 4 argument which can have quite complicated combinations and even be error prone while using by unexperienced users.
For example, call like

array_reserve(target_array, 0, 42, true)

means that vector with 42 string keys will be allocated - it's quite confusing.
Or, as another example, it's easy to mix up int_keys_count and string_keys_count in wrong order.

It's desirable for array_reserve to have some sugar aliases for vector- and map-like arrays to improve user experience:

array_reserve_vector(target_array, capacity);
array_reserve_map_int_keys(target_array, capacity);
array_reserve_map_string_keys(target_array, capacity);

var_dump on a shape type fails during C++ code compilation

An attempt to print a shape-typed value with var_dump will fail with C++ compiler error.
KPHP should probably report such issues during type checking (or in "final check" phase).

It's probably not only about shape types, but about everything that passes a type check and then can't be compiled with gcc.

Array indexing check false positive with explicit isset

Since getting a non-existing element in KPHP leads to different results ("empty value of array type element" instead of null), people sometimes tend to write code like this:

$v = isset($data['k']) ? $data['k'] : '';
if ($v !== '') { // <- warning here
}

It makes sure that for both KPHP and PHP this code could behave identically.

But it looks like KPHP does not recognize this idiom.

Do we have any hints for this case (for example, !empty($v), etc.)?
In that case, we could suggest a potential fix to the problem inside the warning message.

Is it practical to improve this particular diagnostic so it doesn't report such cases?

Consider adding a support for duplicated interfaces in the "implements" chain

This code won't compile with KPHP:

interface Node {}
interface FunctionLike extends Node {}

class Expr implements Node {}
class ArrowFunc extends Expr implements FunctionLike {}

https://github.com/nikic/PHP-Parser/blob/4848a0d734833003eebc969ab395f36b44419f85/lib/PhpParser/Node/Expr/ArrowFunction.php

Error message:

duplicated class: PhpParser\Node in hierarchy from class: PhpParser\Node\Expr\ArrowFunction

I haven't done any investigations yet; just reporting an obstacle I faced. :)

Implement FFI

See for some details #185.

This is an issue for the progress tracking.

Confusing error message for shape unpacking

Code example:

<?php

/**
 * @return shape(foo: int, boo: string)
 */
function f() {
    return shape(["foo" => 1, "boo" => "hello"]);
}

[$a, $b] = f();

Actual Behavior:

Only string const keys can be used, got 'int'

Expected Behavior:

You should explicitly specify the keys for unpacking the shape, for example ['key' => $a] = $shape.

вопрос такой ?

я так понемаю что обновленый компилятор без db получается без движков ?
вопрос второй можно ли от старого kphp-db прицепить к новаму компилятору движки ?

Consider supporting a union of related types as instanceof operand

<?php

class Base {}

class Derived1 extends Base {}
class Derived2 extends Base {}

/** @param Derived1|Derived2 $x */
function f($x) {
  if ($x instanceof Derived1) {
    return 'derived1';
  }
  return 'derived2';
}

var_dump(f(new Derived1()));
var_dump(f(new Derived2()));
Compilation error at stage: Trasform To Smart Instanceof, gen by transform-to-smart-instanceof.cpp:18
  hello.php:10  in f
    if ($x instanceof Derived1) {

left operand of `instanceof` should be instance of class

We already infer f() param as Base; it should be possible to use instanceof as well, like it someone wrote @param Base $x instead of Derived1|Derived2.

Inherited phpdoc is not applied if typehint is used (?)

<?php

class Foo{}

abstract class A {
  /** @return Foo[] */
  public abstract function f() : array;
}

class B extends A {
  public function f() : array { return []; }
}

function test() {
  $b = new B();
  $a = $b->f(); // $a has type array< Unknown >
  var_dump(count($a));
}

test();

It looks like we could use inherited phpdocs more willingly here.

With derived signatures checking enabled, the code above would not compile, so we would have to add an explicit @return annotation:

class B extends A {
+ /** @return Foo[] */
  public function f() : array { return []; }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.