Download

What is it for?

It is a tool for backporting PHP 7 code into PHP 5. It works by parsing the source script (with nikic/php-parser) and transforming the new PHP 7 features into equivalent expressions using PHP 5 syntax. The transformed parts are patched into the original code, so as to retain as much of the original formatting as possible. For example when changing the header of function (type hints, return type), only the modified header is patched back to the original code.

Included is a script for recursive conversion of whole directory.

Usage

Clone repo, run composer install, run php convert.php <source dir> <destination dir>. All *.php files from source dir will be copied to destination dir and backported, retaining the folder structure. No other files will be copied or converted.

Transformations

Currently, these tranformations of PHP 7 structures are supported:

Null Coalesce Operator

Example 1

$foo ?? $bar;

becomes

isset($foo) ? $foo : $bar;

Example 2

42 ?? $bar;

becomes

!is_null(42) ? 42 : $bar;

Return Type Declarations

Example

function foo() : SomeClass {}

becomes

function foo() {}

Scalar Type Declarations

Example

function foo(string $x, SomeClass $y) {}

becomes

function foo($x, SomeClass $y) {}

Spaceship operator (Combined Comparison Operator)

Example

$foo <=> $bar;

becomes

$foo > $bar ? 1 : ($foo < $bar ? -1 : 0);

Anonymous Classes

Example

$util->setLogger(new class("test.log") {

    function __construct($file) {}

    public function log($msg)

    {

        echo $msg;

    }

});

becomes

$util->setLogger(new AnonymousClass_1('test.log'));

 

class AnonymousClass_1

{

    function __construct($file)

    {

    }

    public function log($msg)

    {

        echo $msg;

    }

}

Class declaration is appended to the end of source file. Multiple anonymous classes are numbered accordingly.

intdiv() function

Example

intdiv(10, 3);

becomes

(int) floor(10 / 3);

Complex example

Transformations are applied using operator precedence etc. and even more complex code is transformed correctly.

function foo(string $x, SomeClass $y) : int

{

    return $foo ?? $one <=> $two;

}

becomes

function foo($x, SomeClass $y)

{

    return isset($foo) ? $foo : ($one > $two ? 1 : ($one < $two ? -1 : 0));

}

What is missing?

and other features... Some of them are not trivial to implement.