Problem with using preg_replace_callback - php

i have a problem when i use preg_replace_callback. i have google translator class
and i want to translate all matches using it .
the code was .
$code = preg_replace_callback('/_e\(\'(.*?)\'\)/',create_function(
'$matches',
'return $translator->translate($matches);'),
$code);
when i make var dump for the var $code, i found its string"1" !!!
im sure that im using a right way for the class.
Thanks.

The problem here is scope. Something similar to this would work in JavaScript, but JS and PHP handle scope differently. To access $translator from within the anonymous function's scope, you need to declare it as a global.
<?php
$code = preg_replace_callback('/_e\(\'(.*?)\'\)/',
create_function('$matches',
'global $translator;'.
'return $translator->translate($matches);'),
$code);
?>
If you want to keep the anon as a one-liner, you can use the globals array:
<?php
$code = preg_replace_callback('/_e\(\'(.*?)\'\)/',
create_function('$matches',
"return $GLOBALS['translator']->translate($matches);"),
$code);
?>
If you have PHP 5.3.0 or later, this can be alleviated with closures and use:
<?php
$code = preg_replace_callback('/_e\(\'(.*?)\'\)/',
function($matches) use ($translator) {
return $translator->translate($matches);
}, $code);
?>
This is assuming that $translator was created in the same scope as $code.

In PHP 5.3 you could use a Closure.
<?php
$code = preg_replace_callback(
'/_e\(\'(.*?)\'\)/',
function($matches) use ($translator) {
return $translator->translate($matches);
},
$code
);

Try to also pass the $translator as argument.
This could look like:
$code = preg_replace_callback('/_e\(\'(.*?)\'\)/',create_function(
'$translator,$matches',
'return $translator->translate($matches);'),
$code);
UPDATE: This code example does not work. The replace callback is invoked with only one argument while the anonymous function here expects 2 arguments. The working implementation would be:
$code = preg_replace_callback('/_e\(\'(.*?)\'\)/',create_function(
'$matches',
'global $translator; return $translator->translate($matches);'),
$code);

Related

Function create_function() PHP Deprecated PHP 7.4 [duplicate]

I have used create_function() in my application below.
$callbacks[$delimiter] = create_function('$matches', "return '$delimiter' . strtolower(\$matches[1]);");
But for PHP 7.2.0, create_function() is deprecated.
How do I rewrite my code above for PHP 7.2.0?
You should be able to use an Anonymous Function (aka Closure) with a call to the parent scoped $delimiter variable, like so:
$callbacks[$delimiter] = function($matches) use ($delimiter) {
return $delimiter . strtolower($matches[1]);
};
I would like to contribute with a very simple case I found in a Wordpress Theme and seems to work properly:
Having the following add_filter statement:
add_filter( 'option_page_capability_' . ot_options_id(), create_function( '$caps', "return '$caps';" ), 999 );
Replace it for:
add_filter( 'option_page_capability_' . ot_options_id(), function($caps) {return $caps;},999);
We can see the usage of function(), very typical function creation instead of a deprecated create_function() to create functions.
Automated Upgrade
If anyone needs to upgrade dozens of create_function() cases in their code to anonymous functions, I work on a tool called Rector.
It goes through the code and replaces the create_function with anonymous functions 1:1. It's tested on 30 various cases.
Install
composer require rector/rector --dev
Setup
Let's say you want to upgrade code in the /src directory.
# rector.php
<?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);
};
Run on your code
# this is set run, it only report what it would change
vendor/bin/rector process --config rector.php --dry-run
# this actually changes the code
vendor/bin/rector process --config rector.php
# the "rector.php" config is loaded by default, so we can drop it
vendor/bin/rector process
EDIT: Updated 2020-10-31 with PHP Rector 0.8.x syntax
Since PHP 7.4 you can use an Arrow function:
$callbacks[$delimiter] = fn($matches) => $delimiter . strtolower($matches[1]);
Arrow functions are shorter than anonymous functions, and use the parent scope - so you can refer to $delimiter without passing it in.
This Array of Anonymous functions worked for me, see code below:
// This will be a dynamic name that could
// be used as a function like "namespace".
$dynamic_name = 'my_dynamic_name';
// Here's some variables that you could use in the scope of
// your dynamic anonymous functions.
$outerVariable = 'If I need this varible, I can use it';
$outerVariableTwo = 'If I need this varible, I can use it too!';
// Create an array that we can later use and turn into
// and associative array with our new dynamic anonymous functions.
$dynamicAnonFunctions = [];
// Create the first dynamic function.
$dynamicAnonFunctions[($dynamic_name."_func_one")] = function () use ($outerVariable, $dynamic_name) {
echo 'Running: function <b>'.$dynamic_name .'_func_one()</b>';
echo '<br><br>';
echo $outerVariable;
echo '<br><br>';
echo 'This works :)';
echo '<br><br>';
};
// Create the second dynamic function
$dynamicAnonFunctions[($dynamic_name."_func_two")] = function () use ($outerVariableTwo, $dynamic_name) {
echo '- - - - - - - - - - - - - - - - - - - ';
echo '<br><br>';
echo 'Running: function <b>'.$dynamic_name .'_func_two()</b>';
echo '<br><br>';
echo $outerVariableTwo;
echo '<br><br>';
echo 'This also works :)!';
echo '<br><br>';
};
// Call the functions.
$dynamicAnonFunctions[($dynamic_name."_func_one")]();
$dynamicAnonFunctions[($dynamic_name."_func_two")]();
// Halt execution.
exit();
Just copy this into your script file and you will see the output from the echo statements, then simply remap the function to your own will!
Happy coding =)
The anonymous function solution works, but if the expression to be returned is in a string I think eval should be used.
$callbacks[$delimiter] = eval('return function($matches){return '.$delimiter.' . strtolower($matches[1]);};');

errors function is deprecated PHP 7.3.28? [duplicate]

I have used create_function() in my application below.
$callbacks[$delimiter] = create_function('$matches', "return '$delimiter' . strtolower(\$matches[1]);");
But for PHP 7.2.0, create_function() is deprecated.
How do I rewrite my code above for PHP 7.2.0?
You should be able to use an Anonymous Function (aka Closure) with a call to the parent scoped $delimiter variable, like so:
$callbacks[$delimiter] = function($matches) use ($delimiter) {
return $delimiter . strtolower($matches[1]);
};
I would like to contribute with a very simple case I found in a Wordpress Theme and seems to work properly:
Having the following add_filter statement:
add_filter( 'option_page_capability_' . ot_options_id(), create_function( '$caps', "return '$caps';" ), 999 );
Replace it for:
add_filter( 'option_page_capability_' . ot_options_id(), function($caps) {return $caps;},999);
We can see the usage of function(), very typical function creation instead of a deprecated create_function() to create functions.
Automated Upgrade
If anyone needs to upgrade dozens of create_function() cases in their code to anonymous functions, I work on a tool called Rector.
It goes through the code and replaces the create_function with anonymous functions 1:1. It's tested on 30 various cases.
Install
composer require rector/rector --dev
Setup
Let's say you want to upgrade code in the /src directory.
# rector.php
<?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);
};
Run on your code
# this is set run, it only report what it would change
vendor/bin/rector process --config rector.php --dry-run
# this actually changes the code
vendor/bin/rector process --config rector.php
# the "rector.php" config is loaded by default, so we can drop it
vendor/bin/rector process
EDIT: Updated 2020-10-31 with PHP Rector 0.8.x syntax
Since PHP 7.4 you can use an Arrow function:
$callbacks[$delimiter] = fn($matches) => $delimiter . strtolower($matches[1]);
Arrow functions are shorter than anonymous functions, and use the parent scope - so you can refer to $delimiter without passing it in.
This Array of Anonymous functions worked for me, see code below:
// This will be a dynamic name that could
// be used as a function like "namespace".
$dynamic_name = 'my_dynamic_name';
// Here's some variables that you could use in the scope of
// your dynamic anonymous functions.
$outerVariable = 'If I need this varible, I can use it';
$outerVariableTwo = 'If I need this varible, I can use it too!';
// Create an array that we can later use and turn into
// and associative array with our new dynamic anonymous functions.
$dynamicAnonFunctions = [];
// Create the first dynamic function.
$dynamicAnonFunctions[($dynamic_name."_func_one")] = function () use ($outerVariable, $dynamic_name) {
echo 'Running: function <b>'.$dynamic_name .'_func_one()</b>';
echo '<br><br>';
echo $outerVariable;
echo '<br><br>';
echo 'This works :)';
echo '<br><br>';
};
// Create the second dynamic function
$dynamicAnonFunctions[($dynamic_name."_func_two")] = function () use ($outerVariableTwo, $dynamic_name) {
echo '- - - - - - - - - - - - - - - - - - - ';
echo '<br><br>';
echo 'Running: function <b>'.$dynamic_name .'_func_two()</b>';
echo '<br><br>';
echo $outerVariableTwo;
echo '<br><br>';
echo 'This also works :)!';
echo '<br><br>';
};
// Call the functions.
$dynamicAnonFunctions[($dynamic_name."_func_one")]();
$dynamicAnonFunctions[($dynamic_name."_func_two")]();
// Halt execution.
exit();
Just copy this into your script file and you will see the output from the echo statements, then simply remap the function to your own will!
Happy coding =)
The anonymous function solution works, but if the expression to be returned is in a string I think eval should be used.
$callbacks[$delimiter] = eval('return function($matches){return '.$delimiter.' . strtolower($matches[1]);};');

ErrorException in Util.php line 206: Function create_function() is deprecated [duplicate]

I have used create_function() in my application below.
$callbacks[$delimiter] = create_function('$matches', "return '$delimiter' . strtolower(\$matches[1]);");
But for PHP 7.2.0, create_function() is deprecated.
How do I rewrite my code above for PHP 7.2.0?
You should be able to use an Anonymous Function (aka Closure) with a call to the parent scoped $delimiter variable, like so:
$callbacks[$delimiter] = function($matches) use ($delimiter) {
return $delimiter . strtolower($matches[1]);
};
I would like to contribute with a very simple case I found in a Wordpress Theme and seems to work properly:
Having the following add_filter statement:
add_filter( 'option_page_capability_' . ot_options_id(), create_function( '$caps', "return '$caps';" ), 999 );
Replace it for:
add_filter( 'option_page_capability_' . ot_options_id(), function($caps) {return $caps;},999);
We can see the usage of function(), very typical function creation instead of a deprecated create_function() to create functions.
Automated Upgrade
If anyone needs to upgrade dozens of create_function() cases in their code to anonymous functions, I work on a tool called Rector.
It goes through the code and replaces the create_function with anonymous functions 1:1. It's tested on 30 various cases.
Install
composer require rector/rector --dev
Setup
Let's say you want to upgrade code in the /src directory.
# rector.php
<?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);
};
Run on your code
# this is set run, it only report what it would change
vendor/bin/rector process --config rector.php --dry-run
# this actually changes the code
vendor/bin/rector process --config rector.php
# the "rector.php" config is loaded by default, so we can drop it
vendor/bin/rector process
EDIT: Updated 2020-10-31 with PHP Rector 0.8.x syntax
Since PHP 7.4 you can use an Arrow function:
$callbacks[$delimiter] = fn($matches) => $delimiter . strtolower($matches[1]);
Arrow functions are shorter than anonymous functions, and use the parent scope - so you can refer to $delimiter without passing it in.
This Array of Anonymous functions worked for me, see code below:
// This will be a dynamic name that could
// be used as a function like "namespace".
$dynamic_name = 'my_dynamic_name';
// Here's some variables that you could use in the scope of
// your dynamic anonymous functions.
$outerVariable = 'If I need this varible, I can use it';
$outerVariableTwo = 'If I need this varible, I can use it too!';
// Create an array that we can later use and turn into
// and associative array with our new dynamic anonymous functions.
$dynamicAnonFunctions = [];
// Create the first dynamic function.
$dynamicAnonFunctions[($dynamic_name."_func_one")] = function () use ($outerVariable, $dynamic_name) {
echo 'Running: function <b>'.$dynamic_name .'_func_one()</b>';
echo '<br><br>';
echo $outerVariable;
echo '<br><br>';
echo 'This works :)';
echo '<br><br>';
};
// Create the second dynamic function
$dynamicAnonFunctions[($dynamic_name."_func_two")] = function () use ($outerVariableTwo, $dynamic_name) {
echo '- - - - - - - - - - - - - - - - - - - ';
echo '<br><br>';
echo 'Running: function <b>'.$dynamic_name .'_func_two()</b>';
echo '<br><br>';
echo $outerVariableTwo;
echo '<br><br>';
echo 'This also works :)!';
echo '<br><br>';
};
// Call the functions.
$dynamicAnonFunctions[($dynamic_name."_func_one")]();
$dynamicAnonFunctions[($dynamic_name."_func_two")]();
// Halt execution.
exit();
Just copy this into your script file and you will see the output from the echo statements, then simply remap the function to your own will!
Happy coding =)
The anonymous function solution works, but if the expression to be returned is in a string I think eval should be used.
$callbacks[$delimiter] = eval('return function($matches){return '.$delimiter.' . strtolower($matches[1]);};');

Upgrading from create_function to closures

Struggling to understand closures for a couple of days. Can anybody point me in the right direction? Need to re-write this "create_function" as a lambda.
$section = preg_replace_callback('/{listing_field_([^{}]*?)_caption}/', create_function('$matches', 'global $config,$or_replace_listing_id,$lang;require_once($config[\'basepath\'].\'/include/listing.inc.php\'); return listing_pages::renderSingleListingItem($or_replace_listing_id, $matches[1],\'caption\');'), $section);
You define a closure like so:
$myClosure = function ($args) {
// do something;
};
create_function takes two arguments - the first is an eval'd string of the callable's arguments, the second is the code to execute - so you'd do something like this:
$section = preg_replace_callback(
// Your regex search pattern
'/{listing_field_([^{}]*?)_caption}/',
// Your callback
function ($matches) use ($config, $or_replace_listing_id) {
require_once $config['basepath'] . '/include/listing.inc.php';
return listing_pages::renderSingleListingItem(
$or_replace_listing_id,
$matches[1],
'caption'
);
},
// Your subject
$section
);
Note that I've replaced your global variable calls with importing them via use into the callback instead, and removed $lang because you aren't using it.

How do I implement a callback in PHP?

How are callbacks written in PHP?
The manual uses the terms "callback" and "callable" interchangeably, however, "callback" traditionally refers to a string or array value that acts like a function pointer, referencing a function or class method for future invocation. This has allowed some elements of functional programming since PHP 4. The flavors are:
$cb1 = 'someGlobalFunction';
$cb2 = ['ClassName', 'someStaticMethod'];
$cb3 = [$object, 'somePublicMethod'];
// this syntax is callable since PHP 5.2.3 but a string containing it
// cannot be called directly
$cb2 = 'ClassName::someStaticMethod';
$cb2(); // fatal error
// legacy syntax for PHP 4
$cb3 = array(&$object, 'somePublicMethod');
This is a safe way to use callable values in general:
if (is_callable($cb2)) {
// Autoloading will be invoked to load the class "ClassName" if it's not
// yet defined, and PHP will check that the class has a method
// "someStaticMethod". Note that is_callable() will NOT verify that the
// method can safely be executed in static context.
$returnValue = call_user_func($cb2, $arg1, $arg2);
}
Modern PHP versions allow the first three formats above to be invoked directly as $cb(). call_user_func and call_user_func_array support all the above.
See: http://php.net/manual/en/language.types.callable.php
Notes/Caveats:
If the function/class is namespaced, the string must contain the fully-qualified name. E.g. ['Vendor\Package\Foo', 'method']
call_user_func does not support passing non-objects by reference, so you can either use call_user_func_array or, in later PHP versions, save the callback to a var and use the direct syntax: $cb();
Objects with an __invoke() method (including anonymous functions) fall under the category "callable" and can be used the same way, but I personally don't associate these with the legacy "callback" term.
The legacy create_function() creates a global function and returns its name. It's a wrapper for eval() and anonymous functions should be used instead.
With PHP 5.3, you can now do this:
function doIt($callback) { $callback(); }
doIt(function() {
// this will be done
});
Finally a nice way to do it. A great addition to PHP, because callbacks are awesome.
Implementation of a callback is done like so
// This function uses a callback function.
function doIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
print 'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Displays: Data is: this is my data
One nifty trick that I've recently found is to use PHP's create_function() to create an anonymous/lambda function for one-shot use. It's useful for PHP functions like array_map(), preg_replace_callback(), or usort() that use callbacks for custom processing. It looks pretty much like it does an eval() under the covers, but it's still a nice functional-style way to use PHP.
well... with 5.3 on the horizon, all will be better, because with 5.3, we'll get closures and with them anonymous functions
http://wiki.php.net/rfc/closures
You will want to verify whatever your calling is valid. For example, in the case of a specific function, you will want to check and see if the function exists:
function doIt($callback) {
if(function_exists($callback)) {
$callback();
} else {
// some error handling
}
}
create_function did not work for me inside a class. I had to use call_user_func.
<?php
class Dispatcher {
//Added explicit callback declaration.
var $callback;
public function Dispatcher( $callback ){
$this->callback = $callback;
}
public function asynchronous_method(){
//do asynch stuff, like fwrite...then, fire callback.
if ( isset( $this->callback ) ) {
if (function_exists( $this->callback )) call_user_func( $this->callback, "File done!" );
}
}
}
Then, to use:
<?php
include_once('Dispatcher.php');
$d = new Dispatcher( 'do_callback' );
$d->asynchronous_method();
function do_callback( $data ){
print 'Data is: ' . $data . "\n";
}
?>
[Edit]
Added a missing parenthesis.
Also, added the callback declaration, I prefer it that way.
For those who don't care about breaking compatibility with PHP < 5.4, I'd suggest using type hinting to make a cleaner implementation.
function call_with_hello_and_append_world( callable $callback )
{
// No need to check $closure because of the type hint
return $callback( "hello" )."world";
}
function append_space( $string )
{
return $string." ";
}
$output1 = call_with_hello_and_append_world( function( $string ) { return $string." "; } );
var_dump( $output1 ); // string(11) "hello world"
$output2 = call_with_hello_and_append_world( "append_space" );
var_dump( $output2 ); // string(11) "hello world"
$old_lambda = create_function( '$string', 'return $string." ";' );
$output3 = call_with_hello_and_append_world( $old_lambda );
var_dump( $output3 ); // string(11) "hello world"
I cringe every time I use create_function() in php.
Parameters are a coma separated string, the whole function body in a string... Argh... I think they could not have made it uglier even if they tried.
Unfortunately, it is the only choice when creating a named function is not worth the trouble.

Categories