Cannot use auto-global as lexical variable when I try to use rector code migration

358 views Asked by At

I have old code that I need to migrate to newer PHP versions. This code has many uses of the now deprecated create_function. In order to avoid to update everything manually I have tried to use rector.

I have used this rector configuration file to update all the create_function uses.

<?php

use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Rector\Php72\Rector\FuncCall\CreateFunctionToAnonymousFunctionRector;

return static function (ContainerConfigurator $containerConfigurator) {
    $parameters = $containerConfigurator->parameters();
    $parameters->set(Option::PATHS, [
        __DIR__ . '/src',
    ]);

    $services = $containerConfigurator->services();
    $services->set(CreateFunctionToAnonymousFunctionRector::class);
};

As result rector has replaced sections as

function register_skin_deactivation_hook_function($code, $function) {
    $GLOBALS[ 'register_skin_deactivation_hook_function' . $code] = $function;
    $fn=create_function('$skin', ' call_user_func($GLOBALS["register_skin_deactivation_hook_function' . $code . '"]); delete_option("skin_is_activated_' . $code. '");');
    add_action( 'switch_s' , $fn );
}

with

function register_skin_deactivation_hook_function($code, $function) {
    $GLOBALS[ 'register_skin_deactivation_hook_function' . $code] = $function;
    $fn=function ($skin) use ($GLOBALS, $code) {
            call_user_func($GLOBALS["register_skin_deactivation_hook_function{$code}"]);
            delete_option("skin_is_activated_{$code}");
    };
    add_action( 'switch_s' , $fn );
}

But unfortunately this cause the error

Fatal error: Cannot use auto-global as lexical variable

on

$fn=function ($skin) use ($GLOBALS, $code) {

How could I address this problem?

1

There are 1 answers

0
IMSoP On

This is (or was) a bug in the Rector transform: it has analysed the variables used in your create_function statement, and built the use clause listing all of them.

However, since $GLOBALS is a "super global", it is available in all scopes, so doesn't need to be (and indeed can't be) captured with a use clause.

The correct definition is simply:

function register_skin_deactivation_hook_function($code, $function) {
    $GLOBALS[ 'register_skin_deactivation_hook_function' . $code] = $function;
    $fn=function ($skin) use ($code) {
            call_user_func($GLOBALS["register_skin_deactivation_hook_function{$code}"]);
            delete_option("skin_is_activated_{$code}");
    };
    add_action( 'switch_s' , $fn );
}

(Note: this is a Community Wiki answer based on comments, to avoid the question showing as "unanswered".)