Mikulas / transpiler

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Transpiler

PHP source code transformations operating on abstract syntax tree (AST). This library contains multiple visitors that convert AST of PHP7.1 to PHP7.0-compatible one. Alongside this each release comes with a binary with console utility that transpiles whole worktree in-place.

CircleCI

Console utility installation

Prebuilt package: simple

bash <(curl -sSL 'https://raw.githubusercontent.com/Mikulas/transpiler/v1.1.2/installer.sh')

Prebuilt package: manual

Download release binary from https://github.com/Mikulas/transpiler/releases/latest, put it anywhere in your $PATH and make it executable.

TARGET="/usr/local/bin/php-transpiler"
curl -L 'https://github.com/Mikulas/transpiler/releases/download/v1.1.2/transpiler.phar' -o "$TARGET"
chmod a+x "$TARGET"
export PATH="$PATH:/usr/local/bin"

Dev version

git clone git@github.com:Mikulas/transpiler.git
cd transpiler
git checkout v1.1.2
composer install

Library installation

This library by itself only contains AST modifiers, to convert your codebase, you probably want the console utility instead. If you really need to build on this, add mikulas/transpiler as dependency:

composer require mikulas/transpiler

Usage

php-transpile <paths> (<paths>)... [--verbose]

This command will convert all .php and .phpt files found recursively in paths. Make sure you run this command only when you have no changes in your worktree, otherwise you will lose those changes! Files are transpiled in-place.

What Is It Good For?

By transpiling code to older runtime versions you gain many benefits of PHP 7.1 such as void return types and optionals (which are mostly useful for static analysis), but you are not forced to update production to unstable bleeding-edge versions.

Implemented AST modifiers:

PHP 7.1 → 7.0

Remove void return types

function foo(): void
{
}

# -->

function foo()
{
}

Limitations: ReflectionFunctionAbstract::getReturnType() and hasReturnType() will return NULL and FALSE respectively instead of original values.

Remove class constant visibilities

class Foo
{
    public const A = 'a';
    protected const B = 'b';
    private const C = 'c';
}

# -->

class Foo
{
    const A = 'a';
    const B = 'b';
    const C = 'c';
}

Limitations: none

Rollout named assignment

['X' => ['A' => $a, 'B' => $b]] = ['X' => ['A' => 10, 'B' => 20]];
list('T' => list('U' => $u, 'V' => $v)) = ['T' => ['U' => 15, 'V' => 19]];

while (list($a, $b) = $right) {
    block();
}
# -->

${'~transpiler-1'} = ['X' => ['A' => 10, 'B' => 20]];
$a = ${'~transpiler-1'}['X']['A'];
$b = ${'~transpiler-1'}['X']['B'];

${'~transpiler-2'} = ['T' => ['U' => 15, 'V' => 19]];
$u = ${'~transpiler-2'}['T']['U'];
$v = ${'~transpiler-2'}['T']['V'];

while (${'~transpiler-3'} = $right) {
    $a = ${'~transpiler-3'}[0];
    $b = ${'~transpiler-3'}[1];
    block();
}

Limitations: slightly worse performance, introduces new variable

Dynamic mutating keys are not supported.

[$x++ => $a, $x++ => $b] = [10, 20];

Remove nullable return type

function sum(): ?int
{
}

# -->

function sum()
{
}

Convert nullable parameter

function sum(?int $a, ?int $b)
{
}

# -->

function sum(int $a = NULL, int $b = NULL)
{
}

Remove iterable type

function compute(iterable $arr): iterable
{
}

# -->

function compute($arr)
{
}

Convert Closure::fromCallable

Closure::fromCallable('intdiv');
Closure::fromCallable([$foo, 'bar']);
Closure::fromCallable([Foo::class, 'qaz']);
use Closure as Alias;
Alias::fromCallable($foo($a = $b));

# -->

function () {
    return call_user_func_array('intdiv', func_get_args());
};

function () use(&$foo) {
    return call_user_func_array([$foo, 'bar'], func_get_args());
};

function () {
    return call_user_func_array([\Foo::class, 'qaz'], func_get_args());
};

use Closure as Alias;
function () use(&$foo, &$a, &$b) {
    return call_user_func_array($foo($a = $b), func_get_args());
};

Limitations: Dynamic invocation does not work (such as from call_user_func).

Expand multi catch exception handlers

try {
} catch (FooException | BarException $e) {
    handler();
}

# -->

try {
} catch (\FooException $e) {
    handler();
} catch (\BarException $e) {
    handler();
}

About

License:MIT License


Languages

Language:PHP 97.1%Language:Shell 2.9%