Runkit7: Independent fork of runkit for PHP 7.2+
For all those things you.... probably shouldn't have been doing anyway.... but surely do! Supports PHP7.2-8.1! (function/method manipulation is recommended only for unit testing, but all other functionality works.)
-
Function/method manipulation crashes in PHP 7.4+ when opcache is enabled (e.g.
opcache.enable_cli
) (Issue #217)Disabling opcache is the recommended workaround.
-
This has been tested with php 8.2.0beta1
Building and installing runkit7 in unix
Building and installing runkit7 in Windows
This extension's documentation is available at https://www.php.net/runkit7.
See runkit-api.php for the implemented functionality and method signatures. New functionality was added to support usage with PHP7.
- This adds the ability to set return types (including nullable return types) on added/redefined functions.
- This adds the ability to set
declare(strict_types=1)
on added/redefined functions.
Superglobals work reliably when tested on web servers and tests. Class and function manipulation is recommended only for unit tests.
-
The
runkit.superglobal
ini setting works reliably in PHP 7. -
Manipulating user-defined (i.e. not builtin or part of extensions) functions and methods via
runkit7_method_*
andrunkit7_function_*
generally works, but is recommended only in unit tests (unlikely to crash, but will cause memory leaks) -
Manipulating built in functions may cause segmentation faults in rare cases. File a bug report if you see this. Function and method manipulation is recommended only for debugging or unit tests, because of the possibility of crashes. (Manipulating built in class methods is impossible/not supported)
-
Adding default properties to classes doesn't work in php7, because of a change in the way PHP stores objects. Eventually, I plan to add
runkit_default_property_modify
, which will replace one default value with a different default property, keeping the number of properties the same. See the reasons for disabling property manipulation at PROPERTY_MANIPULATION.md As a substitute, user code can do the following things:- rename (or add)
__construct
withrunkit7_method_rename
/runkit7_method_add
, and create a new version of__construct
that sets the properties, then calls the original constructor. - For getting/setting properties of individual objects, see ReflectionProperty
ReflectionProperty->setAccessible(true)
andReflectionProperty->setValue()
, etc.
- rename (or add)
-
Modifying constants works for constants declared in different files, but does not work for constants within the same file. PHP7 inlines constants within the same file if they are guaranteed to have only one definition. Patching php-src and/or opcache to not inline constants (e.g. based on a php.ini setting) is possible, but hasn't been tried yet.
-
Sandboxing (and
runkit_lint
) were removed.
The following contributions are welcome:
- Pull requests with PHP5 -> PHP7 code migration of functions
- New test cases for features that no longer work in PHP7, or bug reports containing code crashing runkit7.
- Issues for PHP language features that worked in PHP5, but no longer work in PHP7,
for the implemented methods (
runkit7_function_*
andrunkit7_method_*
) - Fixes and documentation.
Other methods and corresponding tests are disabled/skipped because changes to php internals in php7 made them impractical.
This is runkit7 4.x. Use runkit7 2.x for PHP 7.1 support, or 1.x for PHP 7.0 support.
The following mocking libraries work with runkit7.
- timecop-PHP (Fork), a time testing library inspired by the ruby timecop gem (requires
runkit.internal_override=1
, suggested only for unit tests) - staticmock, a mockery-like DSL to replace static methods in tests.
- SimpleStaticMock (Fork), a very simple class to mock static methods in unit tests. Unrelated to tototoshi/staticmock.
- TraceOn (Fork), a simple PHP utility to trace(investigate) invocations of instance/static/global methods.
- There are segmentation faults when manipulating internal functions (a.k.a. "runkit.internal_override=1") (when you rename/redefine/(copy?) internal functions, and call internal functions with user functions' implementation, or vice versa) (and when functions redefinitions aren't cleaned up) Many (but not all) of these crashes have been fixed.
- There are reference counting bugs causing memory leaks.
2 calls to
emalloc
have been temporarily replaced with calls topemalloc
so that tests would not crash during shutdown (and other reasons) - The Zend VM bytecode representation may change in 8.0 betas and in future minor/major PHP releases after 8.0. Any new opcodes added may not work as expected with each new minor php version release.
NOTE: Most runkit7_*()
functions have aliases of runkit_*()
.
runkit7_function_*
: Most tests are passing. There are some memory leaks when renaming internal functions.runkit7_method_*
: Most tests are passing. There are some memory leaks when renaming internal functions.runkit7_zval_inspect
: Partly passing, and needs to be rewritten because of PHP7's zval changes.runkit7_constant_add
works. Other constant manipulation functions don't work for constants accessed within the same file due to the compiler inlining their values for performance.- Runkit superglobals.
(These functions will be missing. Some of these should be possible to implement.)
-
runkit_class_adopt
andrunkit_class_emancipate
Disabled because of bugs related to properties. -
runkit7_import
This had known crashes in php 7.3+, and was removed in runkit7 4.0 because they weren't straightforward to fix. Use runkit7 3.x if you need to continue using this functionality. -
runkit_lint*
Might be possible if this is rewritten to use actual threading: See issue #114 -
runkit7_constant_*
:runkit7_constant_add
works reliably, other methods don't. This works better when the constants are declared in a file separate from the file accessing that constant. -
runkit_default_property_*
Disabled because of bugs related to properties See issue #30 (implement function to modify only) and issue #113 (Manipulate static properties)runkit_default_property_add
has been removed in php7 - it requiresrealloc
ing a different zval to add a property to the property table That would break a lot of things (PHP internals, other PHP modules, etc) -
runkit_return_value_used
: Removed, was not working and unrelated to other features.vld
seems to have a working implementation in the opcode analyzer, not familiar with how it works.
See https://github.com/runkit7/runkit7/issues
Tasks for the near future:
- Replace property manipulation with
runkit_default_property_modify
(#30)
See CONTRIBUTING.md for guidelines on issues and pull requests, as well as links to resources that are useful for php7 module and runkit7 development.
(runkit7 is a fork of https://github.com/zenovich/runkit, implementing php7.2+ support)
Runkit has two groups of features outlined below (Sandboxing was removed in runkit7):
A new .ini entry runkit.superglobal
is defined which may be specified as a simple variable, or list of simple variables to be registered as
superglobals. runkit.superglobal is defined as PHP_INI_SYSTEM and must be set in the system-wide php.ini.
Example:
php.ini:
runkit.superglobal=foo,bar
test.php:
function testme() {
echo "Foo is $foo\n";
echo "Bar is $bar\n";
echo "Baz is $baz\n";
}
$foo = 1;
$bar = 2;
$baz = 3;
testme();
Outputs:
Foo is 1
Bar is 2
Baz is
NOTE: Only a subset of the APIs have been ported to PHP7. Some of these APIs have segmentation faults in corner cases (when runkit.internal_override=On
)
User defined functions and user defined methods may now be renamed, delete, and redefined using the API described at http://www.php.net/runkit
Examples for these functions may also be found in the tests folder.
runkit_lint
was disabled with the rest of the sandbox code due to issues porting it to PHP 7 (Issue #114).
As a replacement for runkit_lint
/runkit_lint_file
try any of the following:
-
php -l --no-php-ini $filename
will quickly check if a file is syntactically valid, but will not show you any php notices about deprecated code, etc. -
opcache_compile_file
may help, but will not show you any notices. -
token_get_all($code, TOKEN_PARSE)
will detect invalid ASTs in php 7.0+ -
Projects such as PHP-Parser (Pure PHP) and php-ast (C module), which produce an Abstract Syntax Tree from php code. Alternately,
token_get_all()
will throw an error for syntax errors if the flagTOKEN_PARSE
is passed in. (Unfortunately, it parses but does not detect erroneous code, e.g. duplicate classes/methods in the same file).// Example replacement for runkit_lint. try { $ast = token_get_all('<?php function foo(){}', TOKEN_PARSE) return true; } catch (ParseError $e) { return false; }
Alternately, you may wish to use a different approach and run a PHP static analyzer such as Phan, Psalm, or PHPStan
pecl install runkit7
can be used to install runkit7 releases published on PECL.
Tarballs can be downloaded from PECL or GitHub.
An example of how to build the latest master branch from source is below:
git clone https://github.com/runkit7/runkit7.git
cd runkit7
phpize
# The sandbox related code and flags have been removed, no need to disable them.
# (--enable-runkit7-modify (on by default) controls function, method, class, manipulation, and will control property manipulation)
# (--enable-runkit7-super (on by default) allows you to add custom superglobals)
# ./configure --help lists available configuration options.
./configure
make
make test
sudo make install
Read https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 and https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2#building_pecl_extensions first. This is just a special case of these instructions.
For PHP7.2+, you need to install "Visual Studio 2017 Community Edition" (or other 2017 edition). For PHP8.0+, you need to install "Visual Studio 2019 Community Edition" (or other 2019 edition). Make sure that C++ is installed with Visual Studio. The command prompt to use is "VS2017 x86 Native Tools Command Prompt" on 32-bit, "VS2017 x64 Native Tools Command Prompt" on 64-bit.
- Note that different visual studio versions are needed for different PHP versions. For PHP 8.0+, use Visual Studio 2019 and vs16 instead.
For 64-bit installations of php7, use "x64" instead of "x86" for the below commands/folders.
After completing setup steps mentioned, including for C:\php-sdk\phpdev\vc14
extract download of php-7.4.11-src (or any version of php 7) to C:\php-sdk\phpdev\vc15\x86\php-7.4.11-src
There are currently no sources providing DLLs of this fork. Runkit7 and other extensions used must be built from source.
Create subdirectory C:\php-sdk\phpdev\vc14\x86\pecl, adjacent to php source directory)
extract download of runkit7 to C:\php-sdk\phpdev\vc14\x86\pecl\runkit7 (all of the c files and h files should be within runkit7)
Then, execute the following (Add --enable-runkit7
to the configure flags you were already using)
cd C:\php-sdk
C:\php-sdk\bin\phpsdk_setvars.bat
cd phpdev\vc15\x86\php-7.4.11\src
buildconf
configure --enable-runkit7
nmake
Then, optionally test it (Most of the tests should pass, be skipped, or be known failures.):
nmake test TESTS="C:\php-sdk\vc14\x86\pecl\runkit7\tests