Function create_function() is Deprecated in PHP 7.2 - How to Migrate?

This post was updated at August 2020 with fresh know-how.
What is new?

Updated Rector YAML to PHP configuration, as current standard.


If there would be "Miss Deprecation of PHP 7.2", create_function() would definitely win. They can be very complex, tricky and very hard convert to PHP code. Moreover without tests.

Do you have over 5 create_function() pieces in your code? Let's see how to migrate them.

Why is this deprecated? Well, the string arguments of few functions behaves like eval() - that's evil.

<?php

create_function("$a", "return $a");
assert("$value == 5");

And what about quotes?

<?php

create_function("$a", "return $a");
create_function('$a', 'return $a');

You don't want to think which if " or ` breaks the code - you want make code.

I think it's a good move, so how do we refactor them? Let's start with simple code:

<?php

$callback = create_function('$matches', "return strtolower(\$matches[1]);");

How would you refactor this to anonymous function?

(Pause for deep thinking...)

<?php

$callback = function ($matches) {
    return strtolower($matches[1]);
};

As you can see:

Also, notice the \$matches$matches. That's because quote escaping.


What about this one?

<?php

create_function('$a,$b', "return \"min(b^2+a, a^2,b) = \".min(\$a*\$a+\$b,\$b*\$b+\$a);");

How would you refactor this to anonymous function?

(Pause for deep thinking...)

<?php

function ($a, $b) {
    return "min(b^2+a, a^2,b) = " . min($a * $a + $b, $b * $b + $a);
};

The "min(b^2+a, a^2,b) = " is still a string, because it was escaped string in a string.

Too easy for you? Damn, you're smart.


Can you handle this?

<?php

create_function('$b,$a', 'if (strncmp($a, $b, 3) == 0) return "** \"$a\" '.
            'and \"$b\"** Look the same to me! (looking at the first 3 chars)";');

How would you refactor this to anonymous function?

(Pause for deep thinking...)

<?php

function ($b, $a) {
    if (strncmp($a, $b, 3) == 0) {
        return "** \"{$a}\" and \"{$b}\"** Look the same to me! (looking at the first 3 chars)";
    }
};

Ok, but you won't make this code snippet I found in Drupal/Wordpress:

<?php

$this->map_xmlns_func = create_function('$p,$n', 'if(strlen($n[0])>0) $xd
    .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');

How would you refactor this to anonymous function?

(Pause for deep thinking...)

<?php

$this->map_xmlns_func = function ($p, $n) use ($xd) {
    if (strlen($n[0]) > 0) {
        $xd .= ":{$n[0]}";
    }
    return "{$xd}=\"{$n[1]}\"";
};

Who did forget use ($xd)? An anonymous function can't access variables that are not passed as arguments, so without this would crash.


And we could continue and continue with more edgy cases... but I bet you're looking for a solution for your specific function. Well, you could ask on StackOverflow (181 results and counting), but posting each of your 10 cases might get you banned. I have good news for you.


Today in 2019 (almost there), you can instantly upgrade your code and it will take you less time to install & run, then read this whole post so far.

Just setup Rector and run it:

composer require rector/rector --dev
use Rector\Php72\Rector\FuncCall\CreateFunctionToAnonymousFunctionRector;
use Rector\Config\RectorConfig;

return function (RectorConfig $rectorConfig): void {
    $rectorConfig->rule(CreateFunctionToAnonymousFunctionRector::class);
};
vendor/bin/rector process src

Happy instant upgrading!




Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!